【问题标题】:Why is std::string's member operator= not lvalue ref-qualified为什么 std::string 的成员 operator= 不是 lvalue ref-qualified
【发布时间】:2020-04-10 14:01:11
【问题描述】:

我最近learned说成员函数可以是ref-qualified,这让我可以写

struct S {
    S& operator=(S const&) & // can only be used if the implicit object is an lvalue
    { 
      return *this; 
    }
};

S operator+(S const &, S const &) { 
  return {}; 
}

从而阻止用户做类似的事情

S s{};
s + s = S{}; // error

但是,我看到 std::string 的成员 operator= does not do this。所以下面的代码编译没有警告

std::string s;
s + s = s;

有允许这样做的理由吗?

如果没有,将来是否可以添加 ref 限定符,或者会以某种方式破坏现有代码?

【问题讨论】:

  • @cigien 为什么不应该这个操作 s + s = s;允许吗?
  • @VladfromMoscow 据我所知,它没有做任何有用的事情。
  • 考虑例如 std::cout
  • @VladfromMoscow 他们可以写std::cout << ( s + s + 'a' );。不确定我是否认为这是一个令人信服的理由。
  • @VladfromMoscow: +== 是不同的运算符。这个问题特别是关于operator=,它会覆盖字符串。因此,没有有用的纯右值 lhs 版本不等同于仅从 = 操作数创建纯右值。

标签: c++ operator-overloading stdstring ref-qualifier


【解决方案1】:

时间可能在此决定中发挥作用。使用 C++11 将 Ref 限定的成员函数添加到该语言中,而 std::string 自 C++98 以来一直存在。更改标准库中某些内容的定义并非易事,因为它可能会不必要地破坏现有代码。这不是一个应该专门研究为什么应该允许这种奇怪的分配的情况(即寻找一个用例)。相反,人们还应该看看为什么应该禁止这种奇怪的分配(即看看好处,并权衡它们与否则工作代码中断时的潜在痛苦)。这种变化多久会在现实的编码场景中产生影响?

看看 cmets,一个提议的用例的反驳是 “他们可以 [另一种方法]。” 是的,他们可以,但如果他们不这样做呢?在最初设计结构时提出替代方案是有成效的 (std::string)。但是,一旦该结构被广泛使用,您就必须考虑当前不使用替代方案的现有代码。对你可能造成的痛苦有足够的好处吗?这种变化真的会经常发现错误吗?在不会触发另一个警告的情况下,此类错误有多常见? (例如,在if 语句的条件中使用赋值而不是相等可能已经产生了警告。)这些是语言设计者要解决的一些问题。 p>

请理解,我并不是说不能进行更改,只是说需要仔细考虑。

【讨论】:

  • 我喜欢你关于发出警告的观点。目前,此代码不会在任何地方触发任何警告。是否有可能暂时弃用它,提供几年的警告,然后完全删除它?
  • @cigien 这也许是可能的。不过,这样的努力是否值得是个问题。我的猜测(只是猜测)是它不会发生。
【解决方案2】:

无法确定为什么标准不禁止您提出的行为,但有一些可能的解释:

  1. 这只是 C++11 中的一个忽略。在 C++11 之前没有 ref-qualified 方法,因此有人忘记了更改标准中的行为。

  2. 保留它是为了向后兼容使用“脏”代码的人,例如:

std::string("a") = "gds";

出于一些奇怪的原因。

关于将来添加这个 - 这是可能的。但首先旧的operator= 必须被弃用,然后再被删除,因为它会导致上面的代码无法编译。即使这样,一些编译器也可能会支持它以实现向后标准兼容性

【讨论】:

  • 还有第三种可能性:没关系。 C++ 不是保姆。它通常不会禁止在奇怪的极端情况下可能有用的代码。
  • @PeteBecker 这就是我的想法。对于我的一生,我想不出任何用例。
  • @PeteBecker:不仅如此。我想说这是一个事实的结合,这些事情很难做到(你必须尝试分配一个prvalue/xvalue),虽然它们没有用,但它们不会使你的代码未定义。内存不会丢失或丢弃,没有人会访问未初始化的对象等。
  • 是的,但它与内置类型不一致。就像,你不能这样做 (5 + 5) = 1 但它适用于 std::string
  • @bartop:在标准库中命名一个可复制/移动分配但不可分配给prvalue的类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-31
  • 1970-01-01
  • 2020-05-03
  • 2016-09-24
  • 1970-01-01
  • 1970-01-01
  • 2019-08-07
相关资源
最近更新 更多