2016-05-31 31 views
-3

当我运行下面的代码:为什么C++标准库运算符接受rvalues?

std::string myString = "I'm a string."; 
const std::string::iterator &myIterator = ++myString.begin(); 
char c = *myIterator; 
std::cout << c << std::endl; 

我得到一个分段错误(O3带编译优化)。我认为这是因为++运营商返回std::string::iterator &而不是std::string::iterator,所以我们得到一个临时的参考。有没有原因为什么这不会导致编译错误?也就是说,为什么不是签名以下?

std::string::iterator &std::string::iterator::operator++() &; 

甚至更​​好,为什么不规范需要以下特征,使我们能够处理没有问题,右值?

std::string::iterator &std::string::iterator::operator++() &; 
std::string::iterator std::string::iterator::operator++() &&; 
+4

[无法重现](https://ideone.com/I9Z8De)。你确定这是因为这些线?在附注中,即使'++'返回引用,'myIterator'也不是引用,因此它将复制值 – Rakete1111

+3

这工作正常。你能发布完整的代码吗? – Sumeet

+0

是的,你是对的。我修改了这个例子,它现在应该会崩溃。 –

回答

0

你已经发布的代码看起来合法的对我说:std::string::iterator myIterator = ++myString.begin();副本迭代器引用到myIterator所以有到无的临时悬挂引用。

我的心理调试的力量告诉我,你的实际代码有两个问题一个:

  • 你的字符串是即使你认为它有它文本实际上是空的。在这种情况下,++begin()无效。
  • 您在之后改变了字符串,您以迭代器复制的方式使迭代器失效。
+0

我的心理预测是代码示例应该是'std :: string :: iterator&myIterator = ++ myString.begin();'在这种情况下实际上存在悬挂参考。 –

+0

良好的调用(尽管我最初也有一个'const')。不过,我仍然不确定为什么应该成功编译。 –

0

@ M.M的评论很有见地。特别是,我的第二个建议会限制库在实现迭代器中的选项,因为迭代器不需要作为右值来增量(参考:http://en.cppreference.com/w/cpp/iterator/next),事实上,std :: string :: iterator可以实现为char *,这是不可递增的作为右值。

选择是否遵循我的第一个建议似乎是一个库实现的决定,因为标准要求迭代器可以做什么,而不是它们不能做什么,以免不必要地限制哪些类型可以用作迭代器。当然,在这一点上,更改实现可能会导致用户代码的重大更改。