【问题标题】:Why a reference is returned in an assignment operator overload?为什么在赋值运算符重载中返回引用?
【发布时间】:2012-04-30 07:50:11
【问题描述】:

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

有人能解释一下吗?

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

【问题讨论】:

  • 你的代码连编译都没有,怎么办?
  • 你是通过引用返回的,你知道吗?
  • @Luchian-它的编译和运行对我来说很好
  • @cppcoder 你有一个过度许可的编译器。这是未定义的行为。
  • 这个问题的答案可以在下面找到。简而言之,eaxstackoverflow.com/questions/1610030/…

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


【解决方案1】:

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

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

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

http://ideone.com/xTDb6

【讨论】:

  • 奇怪的是它不能在 MSVS 上编译。在声明为返回非void 的函数中没有返回语句是合法的(在语法和语义上有效)。只有执行流程的运行时动作到达导致 UB 的函数的关闭 }
  • 如果new char[10] throws 有一个合法的执行路径可以避免UB。恕我直言,MSVS 不编译这个是错误的。
  • @Luchian 您提供的ideone 链接也显示运行时错误,而不是编译错误
  • @cppcoder 这就是我所说的。 MSVS 无法编译,ideone 遇到运行时错误。
  • @LuchianGrigore Re “MS 做对了”:从技术上讲,没有。该标准说,如果函数被实际调用并返回,它只是未定义的行为。在实践中,无论函数是否被调用,我都更喜欢错误,但是在函数永远无法返回的情况下我遇到了问题:如果它立即显而易见(例如,throw 在任何条件之外),那么微软不会抱怨,但如果正文类似于fatalError(),微软将拒绝编译代码,即使不存在或可能发生未定义的行为。
【解决方案2】:

这条规则源于类似这样的代码:

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

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

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

上面的代码打算等同于:

*this = x;
return *this;

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-24
    • 2017-07-09
    • 1970-01-01
    • 2013-05-26
    • 2012-02-22
    • 2013-02-27
    • 1970-01-01
    相关资源
    最近更新 更多