【问题标题】:Overloading assignment operator without return statement没有返回语句的重载赋值运算符
【发布时间】:2013-03-06 15:40:19
【问题描述】:

为什么允许赋值运算符返回void?为什么分配链在这种情况下有效?看一下代码,就很清楚我在说什么了。

代码:

struct Foo
{
   std::string str;

   Foo(const std::string& _str)
   : str(_str)
   {
   }

   Foo& operator=(const Foo& _foo)
   {    
      str = _foo.str;
      //return *this; /* NO RETURN! */
   }
};

int main()
{
   Foo f1("1");
   Foo f2("2");
   Foo f3("3");
   f1 = f2 = f3 = Foo("4");

   std::cout << "f1: " << f1.str << std::endl;
   std::cout << "f2: " << f2.str << std::endl;
   std::cout << "f3: " << f3.str << std::endl;

   return 0;
}

问题:

  1. 为什么这是合法的? (为什么要编译)
  2. 为什么有效?

我在很多地方都读过“赋值运算符应该返回 *this 以便您可以进行赋值链接”,这完全有道理,但是为什么上述工作有效?

试试看:
online c++ workspace with the code from above

【问题讨论】:

  • 它返回Foo&amp;,而不是void

标签: c++ assignment-operator


【解决方案1】:

为什么这是合法的? (为什么要编译)

这是合法的,并且会在您的程序中注入未定义的行为。你的编译器至少应该警告你(如果你设置了足够高的警告级别,我相信它会警告你)。

根据 C++11 标准的第 6.6.3/2 段:

从函数的末尾流出相当于没有值的返回; 这会导致未定义 值返回函数中的行为

唯一的例外是main() 函数,它允许缺少return 语句。根据第 3.6.1/5 段:

main 中的 return 语句具有离开 main 函数的效果(使用自动销毁任何对象) 存储持续时间)并以返回值作为参数调用std::exit如果控制到了尽头 main的没有遇到return语句,效果就是执行

return 0;

最后:

为什么会起作用?

未定义的行为意味着您的程序可能在某些机器上运行,但在其他机器上不运行;或者它今天可以在所有机器上运行,但明天不行;或者它会导致你的程序产生一些奇怪的、不可预测的结果;包括(这是最坏的情况)似乎运行得非常好。

【讨论】:

  • @Dario:不,我不知道。也许出于兼容性原因。也许这在过去有时是允许的,并且可能仍然期望编译器编译遗留代码。虽然这只是一个猜想。我不知道这在 C 中是否允许,但这可能是另一个原因。无论如何,这在 C++ 中绝对是非法的,除了 main() 函数。
  • @Dario - 对于无效代码,C++ 标准要求实现发出“诊断”问题。唯一需要不编译的东西是#error 指令。然而,当某些事情产生未定义的行为时,它仅仅意味着标准没有说明会发生什么;这里就是这种情况。在这种情况下,原因是在更复杂的情况下很难诊断。在某些情况下,一个编译器没有注意到错误,而另一个编译器注意到了;但只要稍作改动,就会反过来。
【解决方案2】:

你所拥有的是未定义的行为,因为你正在离开一个承诺返回某些东西的函数的末尾。

在 C++ 中唯一合法的函数是 int main()(和带参数的版本),因为它在没有 return 语句的情况下隐式返回 0

【讨论】:

    【解决方案3】:

    检查编译后生成的 asm 代码。我的猜测是该函数返回寄存器 AX 中发生的内容(如果我没记错的话,这是 c-call 标准函数实现)。在你的情况下,它恰好是你想要的......如果你添加一些功能来运行你可能会破坏它......

    【讨论】:

      【解决方案4】:

      这是非法的,如果它可以编译,那么它会以某种方式为运行时存储一些奇怪的东西。并且您必须从函数中返回 *this。正确的函数定义如下所示:

      Foo& operator=(const Foo& _foo)
      {    
        if(this == &_foo) /* check for self-assignment */
           return *this;
      
        str = _foo.str;
      
        return *this;
      }
      

      返回 *this 是链式分配的必要条件,例如:

      Foo  x, y, z;
      x = y = z;     /* *this is necessary for this statement */    
      

      【讨论】:

        猜你喜欢
        • 2013-04-29
        • 1970-01-01
        • 2017-07-09
        • 2012-04-26
        • 2014-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-03
        相关资源
        最近更新 更多