从istream输入到char*指针?

15

我正在阅读Bjarne Stroustrup 的《Programming Principles and Practice Using C++》(第二版)。在第660-661页中,作者定义了一个函数如下:

istream& read_word(istream& is, char* buffer, int max)
    // read at most max-1 characters from is into buffer
{
    is.width(max);    // read at most max-1 characters in the next >>
    is >> buffer;     // read whitespace-terminated word,
                      // add zero after the last character read into buffer
    return is;
}

int main()函数中,函数被调用为read_word(cin,s,max);,其中cinstd::cinmax是一个整数,s是一个大小为max的字符数组。

我不理解is >> buffer;是如何工作的。特别地,当我尝试运行代码时,那行代码会出现错误:

C2679 binary '>>': no operator found which takes a right-hand operand of type 'char *' (or there is no acceptable conversion)

这本书中没有用户定义的operator>>或进一步的说明(除了注释)。

我想知道我们是否可以以任何有意义的方式使用类似于is >> buffer;的东西?如果可以,它是如何工作的?还是这是书中的错误?


更新:我正在使用Visual Studio 2022。 我发现该代码在C++14/17下可以成功运行,但在C++20下无法运行。 对于clang和gcc,结果类似。


1
代码看起来不错。https://godbolt.org/z/hjz8YjcKe 如果您添加一个[mre]和完整且未经篡改的生成错误消息输出选项卡,可能会有人注意到我错过的内容。 - user4581301
3
哈!我甚至没有想过尝试C++ 20。没想到有人在使用Visual Studio时会用它。在我上次检查时,它默认(是默认,不是排便,你这个愚蠢的拼写检查器)为C++14,所以我也默认使用了14。也许我对编译器有些偏见,但我没有像拼写检查器那样认为Visual Studio很差。 - user4581301
2个回答

22
在C++20中,接受char*参数的std::basic_istream::operator >>重载(cppreference页面上的第二个重载)已被删除。这个改变无疑会破坏大量现有的代码,甚至包括Bjarne Stroustrup本人提供的示例!C++20的替代方法是使用接受char (&s)[N]参数的函数,但这似乎不太容易理解。一种适应这种改变的方法是将read_word函数重写为模板,这样您将不再需要显式的max参数和对is.width()的调用。
template <size_t N>
std::istream& read_word(std::istream& is, char (&buffer)[N])
{
    is >> buffer;
    return is;
}

然而,正如Alan Birtles的回答中所提到的,你应该放弃使用原始的char[]数组,并开始使用std::string


2
那些现有代码中有多少正确设置了宽度以防止缓冲区溢出呢?在我的职业生涯中,我也不知道有一次使用过这种重载。 - Alan Birtles
1
@Alan 同意。'old' 运算符确实很危险,我可以理解标准委员会为什么要将其删除。(可能是可怕的 gets 函数的 C++ '类似物'?) - Adrian Mole
1
值得注意的是,《原则与实践》的最新版本现在已经相当老了。是时候推出一版新的,涵盖C++17、20(也许还有23)的修订版了。 - user4581301
2
@Quimby,新的C++修订版中有一些重大变化,例如删除了auto_ptr - Alan Birtles
1
@Quimby 我非常确定在 C++20 中还有其他更改会破坏一些现有的代码。对于其他标准版本也可能是如此。 - Adrian Mole
显示剩余2条评论

9

在c++20中,接受原始char指针的流操作符已被替换为接受固定大小char数组的操作符。最简单的解决方案是改用std::string

如果要使用数组,您的代码应该类似于:

template <size_t N>
istream& read_word(istream& is, char (&buffer)[N], int max)
    // read at most max-1 characters from is into buffer
{
    is.width(max);    // read at most max-1 characters in the next >>
    is >> buffer;     // read whitespace-terminated word,
                      // add zero after the last character read into buffer
    return is;
}

请注意,现在最多只会读取N-1个字符,如果Nmax相同,则可以省略maxwidth调用。

max 也应该是 size_t 类型吗? - Chris
1
@Chris streamsize 是最合适的选择,可以参考 https://en.cppreference.com/w/cpp/io/ios_base/width ,但奇怪的是 setw 接受一个 int 参数,可以参考 https://en.cppreference.com/w/cpp/io/manip/setw。 - Alan Birtles

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接