5

为什么赋值运算符允许返回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以便你可以进行赋值链接”,这完全是有道理的,但是为什么上述工作有效呢?

试试看:
使用上面代码的在线 c++ 工作区

4

4 回答 4

8

为什么这是合法的?(为什么它完全编译)

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

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

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

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

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

return 0;

最后:

为什么它有效?

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

于 2013-03-18T10:27:58.577 回答
2

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

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

于 2013-03-18T10:28:24.847 回答
0

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

于 2013-03-18T10:37:22.917 回答
0

这是非法的,如果它编译,那么它以某种方式为运行时存储了一些奇怪的东西。你必须*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-03-18T10:40:37.980 回答