C++ tellg() 不适用于 getline()?
C++ tellg() doesn't work with getline()?
我知道这个标题听起来很疯狂,但我现在亲身经历过,我想不出为什么会失败。
我正在使用getline()读取一个文件
在阅读结束时,我调用tellg()。但是,此调用总是失败(返回值为-1)。
tellg()与getline()不起作用是已知问题还是我做错了什么?
我使用的代码非常简单,基本上是
while(getline(file,line))
{
//tokenize and do other things
}
cout<<file.tellg()<<endl;
有问题的文件是一个普通磁盘上的简单txt文件,我尝试了一个有CRLF和没有CRLF的文件,它没有区别。
编辑:附加信息
gcc/g++4.1.2,Linux(RHEL 5)
第2版:根据此线程:http://www.cplusplus.com/forum/beginner/3599/#msg15540由于某种gcc错误,不可能将tellg与getline一起使用。事实真的是这样吗?(你在互联网上读到的并不总是真的=P)
tellg()
函数的工作原理是尝试构造一个sentint对象,然后在返回正确值之前检查failbit
。如果设置了failbit
,则返回-1。详细信息可以在这里找到,或者,如果你喜欢更官方的来源,并且不介意干读,可以在ISO C++标准(27.6.1.3/36a-37
表示C++03,27.7.2.3/39-40
表示C++11)中找到。
哨兵的构造首先检查任何错误标志(如eofbit
),如果设置了,则设置failbit
并返回。详见此处(C++03 27.6.1.1.2
、C++11 27.7.2.1.3
)、
因此,在设置了文件结束标志之后的tellg()
将失败。在getline
返回false之前,您一直在读取行,这意味着流的eofbit
正在被设置,因此您已经到达了文件的末尾。
您可以看到以下程序的行为:
#include <iostream>
#include <iomanip>
int main (void) {
std::string line;
while (std::getline (std::cin, line)) {
if (line.length() > 20)
line = line.substr(0,17) + "...";
std::cout << "tellg() returned "
<< std::setw(5) << std::cin.tellg()
<< " after " << line << "n";
}
//std::cin.clear();
std::cout << "tellg() returns: "
<< std::cin.tellg() << 'n';
return 0;
}
当你运行它并提供文件本身作为输入时,你会看到:
tellg() returned 20 after #include <iostream>
tellg() returned 39 after #include <iomanip>
tellg() returned 40 after
tellg() returned 58 after int main (void) {
tellg() returned 80 after std::string l...
tellg() returned 124 after while (std::g...
tellg() returned 156 after if (line....
tellg() returned 202 after line ...
tellg() returned 243 after std::cout...
tellg() returned 291 after << st...
tellg() returned 333 after << " ...
tellg() returned 339 after }
tellg() returned 363 after //std::cin.cl...
tellg() returned 400 after std::cout << ...
tellg() returned 437 after << std::c...
tellg() returned 451 after return 0;
tellg() returned 453 after }
tellg() returned 454 after
tellg() returns: -1
如果您取消注释代码中清除错误状态变量的行,它将起作用:
tellg() returned 20 after #include <iostream>
tellg() returned 39 after #include <iomanip>
tellg() returned 40 after
tellg() returned 58 after int main (void) {
tellg() returned 80 after std::string l...
tellg() returned 124 after while (std::g...
tellg() returned 156 after if (line....
tellg() returned 202 after line ...
tellg() returned 243 after std::cout...
tellg() returned 291 after << st...
tellg() returned 333 after << " ...
tellg() returned 339 after }
tellg() returned 361 after std::cin.clea...
tellg() returned 398 after std::cout << ...
tellg() returned 435 after << std::c...
tellg() returned 449 after return 0;
tellg() returned 451 after }
tellg() returned 452 after
tellg() returns: 452
顺便说一句,你所指的bug可能就是这个(这有点不清楚,因为你链接的帖子很遗憾地缺少了任何细节——如果发帖者愿意支持他声称这是一个已知的bug,例如链接,那就更好了)。
如果是这样的话,你应该注意的第一件事是,它在十多年前就被修复了,所以,除非你使用的是一个绝对古老的gcc
,否则它现在不会成为问题。
std::istream::tellg
在设置流的错误标志时不会告诉您任何信息。根据其规格,
返回:构造哨兵对象后,如果是
fail() != false
,则返回pos_type(-1)
表示失败。否则,返回rdbuf()->pubseekoff(0, cur, in)
。
参照std::istream::sentry
,如果已经设置了eof
,则设置fail
。
但是fail
和eof
被clear
函数清除,这就是您所需要做的
while(getline(file,line))
{
//tokenize and do other things
}
file.clear(); // reset error state
cout<<file.tellg()<<endl;
即使你不使用clear
,pubseekoff
功能仍然有效,所以这也有效:
cout<< static_cast< std::streamoff >( file.rdbuf()->pubseekoff(0, std::ios::cur, std::ios::in) )
<<endl;
- FLTK 2.0构建和演示,适用于VS2019的2011年左右的代码库
- C++17 - 使用自定义分配器的节点提取/重新插入 - 适用于 clang++/libc++,但不适用于 libstd
- "string.h"在构建适用于iOS的qt应用程序中找不到消息
- 适用于 WebView2 旧版本的示例应用程序
- 在 NVIDIA GEFORCE GTX 1050 上下载适用于 Windows 10 的 openCL 1.2
- __attribute__(优化(0))) 是否适用于"recursively"?
- 为什么 std::erase(std::erase_if) 不是适用于<algorithm>任何容器的模板?
- 使用一个参数的模板函数时出错(适用于 2)
- 使用 适用于 Android 和 iOS 的 tf-lite C++ API
- 为什么这适用于 G++ 而不是 CLANG?
- 适用于 macOS 的 Xcode 应用程序。这就是我设置从USB麦克风输入获取音频的方式。一年前工作,现在没有了。为什么
- 适用于 Linux 的 c++ 上的代理脚本
- 为什么我的 SFINAE 表达式不再适用于 GCC 8.2?
- 使输出流式处理运算符适用于 boost::variant<std::vector<int>、int、double 的正确方法是什么>
- 有没有适用于Windows.lib文件的GNU二进制文件描述符(BFD)
- 模板函数仅适用于VS
- 如何在cmake中包含适用于g++或viceversa的库
- 适用于win32、linux、mac的POSIX C包装器
- WinDBG适用于从Visual Studio 2015保存的转储,但不适用于任务管理器。显示异常代码"not found"
- 从uint8_t到NPY_UINT16 PyArray_SimpleNewFromData.适用于Linux,但不适用于