【问题标题】:C++ why the assignment operator should return a const ref in order to avoid (a=b)=cC++ 为什么赋值运算符应该返回一个 const ref 以避免 (a=b)=c
【发布时间】:2011-06-10 01:15:27
【问题描述】:

我正在读一本关于 C++ 的书,更准确地说是关于运算符重载的书。

示例如下:

const Array &Array::operator=(const Array &right)
{
// check self-assignment
// if not self- assignment do the copying
return *this; //enables x=y=z
}

书中提供的关于返回 const ref 而不是 ref 的解释是为了避免像 (x=y)=z 这样的赋值。我不明白我们为什么要避免这种情况。我知道在此示例中首先评估 x=y ,并且由于它返回一个 const 引用,因此 =z 部分无法执行。但为什么呢?

【问题讨论】:

  • 哪本书?这对我来说似乎是不必要的预防措施。我无法想象有人写(x=y)=z——他们为什么要写?如果没有括号,x=y=z 将被解析为 x=(y=z),这非常合理,因此没有风险。
  • 但是为什么呢?为什么它是一个常量引用?为什么按这个顺序执行?为什么不能将z 分配给 (x=y)?
  • @antronis:获得更好的 C++ 书籍。
  • 这是deitel c++如何编程第7版
  • 我同意这不是你通常会写的东西,但如果你的意思是(x = y) == z 并且打错了怎么办?我也不赞同那个特定的表达式,但是做更多的事情 const 有助于将运行时错误转化为编译时错误,这通常是有帮助的。

标签: c++ operator-overloading assignment-operator


【解决方案1】:

没有必要避免这种情况,除非本书的目标读者是那些通常写成(x=y)=z 的程序员,而他们的意思是x=y=z。在实践中,没有人在他们正常的头脑中写下这个,所以预防措施是完全没有必要的。它还禁止一些其他简洁的结构,例如 (x=y).nonConstMember(),几乎没有人写,但在某些情况下可能有用(尽管它们不应该被过度使用)。

@ybungalobill 是对的,买一本更好的书。

【讨论】:

  • +1。程序员“不小心”写 (x=y)=z 似乎与程序员在意为 x=y 时不小心写 x=y+system("rm -rf /") 一样可能(并且有必要防止)。
  • 但我见过if ((x = y) = z) ...,作者的意思是if ((x = y) == z) ...
【解决方案2】:

我能看到的唯一原因是这本书是为了向 C 程序员(或对 C 理解优于 C++ 理解的作者)解释 C++ 而写的。因为对于 C 程序员来说,表达式(x = y) = z 对于内置类型是无效的,他可能会尝试使用它的用户定义类型来获得相同的行为。

但是,C 和 C++ 是不同的语言,在 C++ 中,表达式 (x = y) = z 即使对于内置类型也是有效的。因此,如果您希望用户定义的类型具有相同的行为,您应该在 operator = 中返回一个非常量引用。

我建议你买一本更好的书,一本不会混淆 C 和 C++ 的书。它们不是同一种语言,即使它们来自一个共同的基础。

【讨论】:

    【解决方案3】:

    我会看看内置类型的行为。

    在定义您自己的类型时,运算符的行为方式最好与内置类型相同。这样可以轻松地采用您的类,而无需深入研究您的代码以了解它们的行为与预期不同的原因。

    所以如果我们看整数:

    int main()
    {
        int x = 5;
        int y = 6;
        int z = 7;
    
        (x = y) = z;
        std::cout << x << " " << y << " " << z << "\n";
    }
    

    这适用于 y 不变且 x 被分配 7。在您的代码中,我希望您的赋值运算符以相同的方式工作。标准赋值运算符定义:

    Array& Array::operator=(Array const& rhs)
    {
        /* STUFF */
        return *this;
    }
    

    应该这样做就好了(假设 /* STUFF */ 是正确的)。

    【讨论】:

      【解决方案4】:

      据我所知,赋值运算符在惯用的 C++ 中不返回 const 引用。标准类型也不返回 const 引用。

      std::string a, b, c;
      (a = b).clear(); // no objection from compiler
      

      我所有的自定义赋值运算符都返回了一个非常量引用。

      如有疑问,请查看标准库。它不是完美无缺的,但它肯定会正确地处理这样的基本问题。

      【讨论】:

      • Boost 人通常也返回可变引用。
      【解决方案5】:

      (x=y) 表示x.operator=(y),它返回对象x。因此,(x=y)=z 表示(x.operator=(y)).operator=(z)。括号中的表达式将x 设置为y 并返回x,然后外部位将x 设置为z。它没有像您所期望的那样将y 设置为z,也没有像表达式x = y = z 那样设置。

      这种行为是违反直觉的(赋值后它们应该都相等,对吧?);返回一个 const 引用使其成为不可能并避免了该问题。

      【讨论】:

      • 虽然这种行为听起来违反直觉,但这并不是一个“问题”,因为这是程序员有意为之(这就是他们使用括号的原因)
      • 谁会期望(x=y)=zy 设置为z?这是一个非常人为的“问题​​”,一本 C++ 书籍不应该花时间解释预防措施。 (x=5)=z 没有将 5 设置为 z
      • 如果你期望赋值是关联的(就像比较一样),你会期望最后三个都是相等的。幼稚,但合理的第一眼解释。我同意这种形式一般不应该使用,也不应该在书中强调,但是帮助编译器帮助你尽可能地在脚上开枪是很好的=)
      • 关于赋值首先要理解的是它不是关联的。我看过的每一本命令式编程教科书都在第 1 章或第 2 章中解释了这一点。您对错误输入 (x=y) == z 的评论更有意义。
      • 可能不直观。 但是 这正是它处理整数的方式。我认为模仿标准类型的行为比试图保护人们免受晦涩的情况更重要。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-02
      • 2012-05-29
      • 1970-01-01
      • 2015-11-14
      • 1970-01-01
      • 2012-09-03
      相关资源
      最近更新 更多