C++ getline() 的未记录行为

标签 c++ stream getline stringstream istringstream

在 C++ 中,当您在 stringstream 上使用带分隔符的 getline() 时,有一些我没有发现的记录,但它们在以下情况下有一些非错误的方便行为:

  • 未找到分隔符 => 然后简单地返回整个字符串/其余部分
  • 有分隔符,但之前没有分隔符 => 返回空字符串
  • 获取不存在的内容 => 返回最后可以用它读取的内容

一些测试代码(简化版):

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

string test(const string &s, char delim, int parseIndex ){
    stringstream ss(s);
    string parsedStr = "";
    
    for( int i = 0; i < (parseIndex+1); i++ ) getline(ss, parsedStr, delim);
    
    return parsedStr;
}

int main() {
    stringstream ss("something without delimiter");
    string s1;
    getline(ss,s1,';');
    cout << "'" << s1  << "'" << endl; //no delim
    cout << endl;
    
    string s2 = "321;;123";
    cout << "'" << test(s2,';',0) << "'" << endl; //classic
    cout << "'" << test(s2,';',1) << "'" << endl; //nothing before
    cout << "'" << test(s2,';',2) << "'" << endl; //no delim at the end
    cout << "'" << test(s2,';',3) << "'" << endl; //this shouldn't be there
    cout << endl;
    
    return 0;
}

测试代码输出:

'something without delimiter'

'321'
''
'123'
'123'

测试代码 fiddle :http://ideone.com/ZAuydR

问题

问题是 - 这可以依赖吗?如果是这样,它在哪里记录 - 是吗?

感谢您的回答和澄清:)

最佳答案

getline 的行为明确记录在标准 (C++11 §21.4.8.9 ¶7-10) 中,这是关于 C++ 的唯一规范性文件。

您在前两个问题中询问的行为是有保证的,而第三个问题是您的测试装置的制作方式的结果。

template<class charT, class traits, class Allocator>
  basic_istream<charT,traits>&
    getline(basic_istream<charT,traits>& is,
            basic_string<charT,traits,Allocator>& str,
            charT delim);
template<class charT, class traits, class Allocator>
   basic_istream<charT,traits>&
   getline(basic_istream<charT,traits>&& is,
           basic_string<charT,traits,Allocator>& str,
           charT delim);

Effects: Behaves as an unformatted input function (27.7.2.3), except that it does not affect the value returned by subsequent calls to basic_istream<>::gcount(). After constructing a sentry object, if the sentry converts to true, calls str.erase() and then extracts characters from is and appends them to str as if by calling str.append(1, c) until any of the following occurs:

  • end-of-file occurs on the input sequence (in which case, the getline function calls is.setstate(ios_base::eofbit)).
  • traits::eq(c, delim) for the next available input character c (in which case, c is extracted but not appended) (27.5.5.4)
  • str.max_size() characters are stored (in which case, the function calls is.setstate(ios_base::failbit)) (27.5.5.4)

The conditions are tested in the order shown. In any case, after the last character is extracted, the sentry object k is destroyed.

If the function extracts no characters, it calls is.setstate(ios_base::failbit) which may throw ios_base::failure (27.5.5.4).

Returns: is.

回答您的问题:

delimiter is not found => then simply whole string/rest of it is returned

这是第一个退出条件的结果 - 当输入字符串终止时,字符串流进入文件末尾,因此提取终止(在将所有前面的字符添加到输出字符串之后)。

there is delimiter but nothing before it => empty string is returned

这只是第二点的特例 - 当找到分隔符时提取终止( traits::eq(c, delim) 通常归结为 c==delim ),即使之前没有提取其他字符也是如此。

getting something that isn't really there => returns the last thing that could be read with it

它并不完全像这样。如果流处于错误状态(sentry 对象不会转换为 true ,在上面的描述中) - 在您的情况下,您有一个 EOF -, getline留下你的字符串并返回。在您的测试代码中,您看到最后读取的数据只是因为您正在回收相同的字符串而没有在各种测试之间清除它。

关于C++ getline() 的未记录行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32298240/

相关文章:

c++ - 如何在 C++ 中编写整数和平凡类型之间的双向映射?

c++ - "istreambuf_iterator"后读取文件失败

c++ - [方括号]和*星号之间的区别

c++ - 从另一个线程读取标准输入

c++ - 在 C++ 中有选择地读取格式化的数据文件

java - 为什么 Java 读取大文件的速度比 C++ 快?

java - 从 ObjectInputStream 读取与写入 ObjectOutputStream 不同的 byte[]

java - 从java中的套接字流读取文本和二进制文件时出现奇怪的字符

ios - AVPlayer试图在HLS音频流中找到错误的位置

c++ - cin.ignore 的 getline 问题