0

我读到,从重载的赋值运算符返回引用以启用运算符链接。但是如果没有那个返回,操作符链接似乎也可以工作。

有人可以对此有所了解吗?

class A
{
    public:
        int x,y;
        char* str;

        //Default Constructor
        A(){}

        //Constructor
        A(int a, int b, char* s){
            cout<<"initialising\n";
            x = a;
            y = b;
            str = new char[10];
            str = s;
        }

        //Destructor
        ~A(){}

        //Overloaded assignment operator
        const A& operator=(const A& obj)
        {
            cout<<"Invoking Assignment Operator\n";
            x = obj.x;
            y = obj.y;
            str = new char[10];
            str = obj.str;

            //return *this;
        }
};

ostream& operator<<(ostream& os, const A& obj)
{
    os <<"X="<< obj.x<<" Y="<<obj.y<<" Str="<<obj.str<<"\n";
    return os;
}

int main()
{
    A c(3,4,"Object C");
    cout<<c;

    A d, e, f;
    d = e = f = c;  //Assignment operator invoked 3 times
    cout<<e;
}

输出:

initialising
X=3 Y=4 Str=Object C
Invoking Assignment Operator
Invoking Assignment Operator
Invoking Assignment Operator
X=3 Y=4 Str=Object C
4

2 回答 2

3

您遇到了未定义的行为,因为预期的返回类型operator =const A&并且您没有返回任何内容。

不幸的是它对你有用。(是的,不走运,因为似乎有效的未定义行为是最糟糕的)

我在 MSVS 中遇到编译错误,并且 ideone.com 遇到运行时错误。

http://ideone.com/xTDb6

于 2012-04-30T07:54:37.097 回答
2

这条规则起源于这样的代码:

struct Foo { 
    Foo& copy(const Foo& x) { 
        return (*this = x); 
    } 
};

那时,C++ 有两点不同:

  1. 编译器生成的 operator= 默认返回一个右值,并且
  2. 编译器允许非常量引用绑定到临时对象。

上面的代码旨在等效于:

*this = x;
return *this;

但是,它不是——因为operator=返回了一个右值,编译器生成了一个临时值来保存赋值的结果,然后由于函数返回了一个引用,它返回了一个对该临时值的引用。然后,当然,事情很快就变糟了,因为你现在有一个悬空引用,指向一个在创建它的完整表达式结束时被销毁的临时引用。简而言之,这是一个返回对局部变量的引用的类案例——除了需要进行大量分析才能意识到正在生成局部变量,更不用说返回对它的引用了。

如果你定义你operator=返回一个值而不是一个引用,它将不得不生成一个临时的,就像编译器在上面的代码中所做的那样。我还没有仔细考虑其余部分,以确定当前语言中的其他更改是否足以在这种情况下保护您,但我的直接反应是,您正在重建那个古老的错误大约一半,所以除非你在这件事上绝对别无选择,否则我会远离。

于 2012-04-30T08:20:49.003 回答