可以将std::getline()与从std::string中移出的字符串一起使用吗
Ok to use std::getline() with a moved-from std::string?
std::getline(std::istream&, std::string&)
的第二个参数是引用从std::string
移动的的左值是否安全且定义良好?如果是,该字符串是否从其从移动的状态恢复,以便可以安全地调用pop_back()
等方法?
更简单地说,用getline()
写入字符串是否与分配给该字符串具有等效的语义?
或者更具体地说,以下(有些做作的)片段定义明确且正确吗?
std::ifstream f("foo.txt");
std::vector<std::string> lines;
for (std::string s; std::getline(f, s); lines.push_back(std::move(s)))
if (!s.empty() && s.back() == 'r')
s.pop_back();
使用g++
和clang++
对该代码段进行优化(-march=native -O3
)构建似乎可以按预期工作,但这当然不能保证。
我想知道这是否只依赖于根据C++11标准中getline()
的语义定义良好的行为,或者,如果不是,它是否由该标准的后续版本定义良好,或者,否则,它是否至少由任何/所有主要实现(G++、Clang++、Visual C++、英特尔C++编译器)明确定义。
注意:这是而不是之前问题的重复,该问题询问分配给从对象是否安全(是的,如果是琐碎类型或STL类型),因为getline()
不是赋值运算符。
您的代码是安全的,但这只是因为您正在检查getline
是否成功地将某些内容存储在s
中。如果getline
内部的哨兵未能初始化,则不会向s
分配任何内容,并且它将处于有效但未指定的状态。只要getline
成功地将s
设置为已知状态,就可以了。
并且getline
在成功构建哨兵之后所做的第一件事就是将s
设置为零大小(已知状态)。
更多详情请参阅GManNickG的评论。
std::getline(std::istream&, std::string&)
的第二个参数是引用从std::string
移动的
是。尽管如此,根据[string.cons]p2:的标准,移动的字符串未指定
[…]。在第二种形式中,
str
处于有效状态,但具有未指定的值。
字符串仍然处于有效状态,只是未指定,即您不知道它处于哪个状态(中可能填充了一些随机字符)。您仍然可以将它传递给std::getline
,因为标准在[string.io]p1中说,str.erase()
是在字符串上调用的,这会清空它:
[…]调用
str.erase()
[…]
(如果流是有效的,但我认为这是您的情况)。
无论字符串的未指定状态是什么,它都会在std::getline
开始时清空,所以它处于什么状态都无关紧要。
移动赋值或移动c'tor应始终使移动的对象处于有效状态。
在std::字符串的情况下,当您std::move
它时,它将保持为有效但未指定的字符串。来自libc++的来源:
// __str is a valid, but unspecified string.
basic_string(basic_string&& __str) noexcept
: _M_dataplus(_M_local_data(), std::move(__str._M_get_allocator()))
由于getline()
只在字符串中添加字符,因此只要成功,输出就会如预期的那样。来自cplusplus.com:
请注意,调用之前str中的任何内容都将被新提取的序列替换。
每个提取的字符都被附加到字符串中,就好像调用了其成员push_back一样。
- 我可以重新分配/覆盖std::字符串吗
- 如何将这个std::字符串转换为std::基本字符串
- std::字符串与 PCWSTR 的对话
- 重载 std::字符串运算符+ 用于打印枚举名称
- 从std::字符串创建OssBitString
- std::字符串擦除以删除最后一个字母
- 如何使用 C++ 中的原语初始化类(如 std::字符串从 const char* 初始化)
- std::字符串串联操作
- 如何有效地将一个大std::字符串的一部分转换为float
- 转义std::字符串中的特殊字符
- 用C++替换std::字符串中的一个子字符串,但不能全部替换
- C++std::字符串流到常量字符*的转换
- 如何将std::字符串转换为不同的字符串类
- 对齐C++字符串类型问题 std::字符串到 TStr
- std::字符串到字符*而不切割字节
- 编写具有非ASCII数据的std ::字符串
- 将 Delphi 的字符串转换为 std::字符串用于C++
- std::字符串添加到字符*
- 字符* 和 std::字符串和常量字符*之间的转换
- 用指针访问std ::字符串中的元素