【问题标题】:Why do the C++ standard library operators accept rvalues?为什么 C++ 标准库运算符接受右值?
【发布时间】:2016-05-31 04:38:13
【问题描述】:

当我运行以下代码时:

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 &amp; 而不是std::string::iterator,所以我们得到一个临时引用。是否有理由不执行此操作以导致编译错误?即,为什么不是下面的签名?

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

或者更好的是,为什么规范不需要以下签名以便我们可以毫无问题地处理右值?

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

【问题讨论】:

  • Cannot reproduce。你确定是因为那些线吗?附带说明,即使++ 返回引用,myIterator 也不是引用,因此它会复制值
  • 这工作正常。你能发布完整的代码吗?
  • 我同意包含这些重载会避免错误...但是对整个标准库始终如一地这样做将是一场噩梦,并且可能还会对现有代码进行重大更改。在声明 const 引用时,您可能会坚持记住要小心(而且,没有任何理由对迭代器使用 const 引用 - 它们被设计为轻量级并按值传递)。
  • IMO 首先允许 ++ 用于纯右值有点可疑,内置 ++ 只能用于左值。但很多人似乎对此很满意。
  • 事实上,这是关于这段代码是否可以编译的实现细节:一个库可以使用char *作为字符串迭代器。

标签: c++ operators std rvalue temporary-objects


【解决方案1】:

您发布的代码在我看来是合法的:std::string::iterator myIterator = ++myString.begin(); 复制迭代器引用到 myIterator,因此没有对临时对象的悬空引用。

我的心理调试能力告诉我,您的实际代码存在以下两个问题之一:

  • 您的字符串实际上是空的,即使您认为其中包含文本。在这种情况下,++begin() 无效。
  • 在之后对字符串进行变异,以使迭代器无效。

【讨论】:

  • 我的心理预测是代码示例应该是std::string::iterator&amp; myIterator = ++myString.begin();,在这种情况下实际上有一个悬空引用。
  • 好电话(虽然我最初也有一个const)。不过,我仍然不确定为什么它应该成功编译。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 2011-06-15
    • 2011-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-14
    • 1970-01-01
    相关资源
    最近更新 更多