重载没有返回语句的赋值操作符
Overloading assignment operator without return statement
为什么允许赋值操作符返回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;
}
问题:
- 为什么这是合法的?(为什么它会编译)
- 为什么它工作?
我在很多地方读到"赋值操作符应该返回*这个,这样你就可以有赋值链",这完全有意义,但是为什么上面的工作?
试一试:
使用上面代码的在线c++工作空间
为什么这合法?(为什么它可以编译)
这是不合法的,并且在你的程序中注入了未定义行为。你的编译器至少应该警告你(我相信它会,如果你设置了一个足够高的警告级别)。
根据c++ 11标准第6.6.3/2段:
从函数末尾流出相当于没有返回值;的结果是undefined.
唯一的例外是main()
函数,它允许缺少return
语句。第3.6.1/5段:
最后
main
中的return语句具有离开main
函数的效果(自动销毁任何对象)存储持续时间),并以返回值作为参数调用std::exit
。如果控制到达结束在没有遇到返回语句的情况下执行main
,效果是执行return 0;
:
为什么它工作?
未定义行为意味着你的程序可以在某些机器上运行,但不能在其他机器上运行;或者它今天可以在所有的机器上运行,但不是明天;或者它会导致你的程序产生一些奇怪的、不可预测的结果;包括(这是最糟糕的情况)似乎运行得很好。
您所拥有的是未定义行为,因为您正在流出承诺返回某些内容的函数的末尾。
在c++中唯一合法的函数是int main()
(和带参数的版本),因为它在没有return语句的情况下隐式返回0
。
检查编译后产生的asm代码。我的猜测是,这个函数返回什么发生在寄存器AX(这是c-call标准函数实现,如果我没弄错的话)。在你的情况下,它恰好是你想要的……
这是非法的,如果它编译了,那么在某种程度上它为运行时存储了一些奇怪的东西。并且必须从函数返回*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 */
- c++中的重载赋值操作符
- c++类继承和赋值操作符
- 带引用类成员的赋值操作符
- 复制构造函数,赋值操作符重载
- c++派生类赋值操作符
- 通过调用Move赋值操作符实现Move构造函数
- 带有映射的赋值操作符
- 单参数构造函数和赋值操作符
- 如何从复制赋值操作符调用复制构造函数
- c++复制构造函数,重载赋值操作符,方法get()
- 用于具有const数据成员的类的move和右值赋值操作符
- 类赋值操作符和复制构造函数
- 赋值操作符重载
- 影响正确性的move构造函数/赋值操作符示例
- 当类是子类时重载赋值操作符
- 如果没有定义Move语义(Move构造函数和Move赋值操作符),编译器是否默认优化
- 在类赋值操作符函数中,为什么必须返回*this ?
- 模板类的重载赋值操作符
- 使用重载赋值操作符
- 重载没有返回语句的赋值操作符