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();
此-march=native -O3
和g++
此代码段的优化(clang++
)版本似乎按预期工作,但这当然不能保证。
我想知道这是否只依赖于明确定义的行为,根据C ++ 11标准中getline()
的语义,或者,如果不是,它是否依赖于由标准的后续版本明确定义,或者,如果不是,它至少由任何/所有主要实现(G ++,Clang ++,Visual C ++,英特尔C ++编译器)明确定义。
注意:这是 不 与以前的问题重复,询问是否可以安全地分配给移动的对象(是的,如果它&#39 ; sa琐碎或STL类型)因为getline()
不是赋值运算符。
答案 0 :(得分:8)
您的代码是安全的,但这只是因为您正在检查getline
是否已在s
中成功存储了某些内容。如果getline
内部的哨兵未能初始化,则不会将任何内容分配给s
,并且它将保留在有效但未指定的状态。只要getline
成功将s
设置为已知状态,您就会很好。
成功完成哨兵训练后getline
的第一件事就是将s
设为零(一个已知状态)。
以下更多详情请参阅GManNickG的评论。
答案 1 :(得分:5)
的左值
std::getline(std::istream&, std::string&)
的第二个参数是否安全且定义明确是一个引用移动std::string
是。虽然根据[string.cons]p2标准,未移动的字符串未指定:
[...]。在第二种形式中,
str
处于具有未指定值的有效状态。
字符串仍然处于有效状态,它只是未指定,即你无法知道它所处的状态(可能填充了一些随机字符)。您仍然可以将其传递给std::getline
,因为标准在[string.io]p1中说明在字符串上调用了str.erase()
,这会清空它:
[...]致电
str.erase()
[...]
(如果流有效,但我认为这是你的情况)。
无论字符串的未指定状态是什么,它都会在std::getline
的开头清空,因此它处于什么状态并不重要。
答案 2 :(得分:1)
移动分配或移动c应始终使移动的对象保持有效状态。
如果是std :: string,当它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一样。