引用vs对象作为运算符重载的返回值

时间:2014-02-15 14:25:19

标签: c++ object reference overloading operator-keyword

我正在尝试在C ++中重载二元+运算符。 现在,我认为在重载运算符时返回对Object的引用是错误的,因为尽管在方法结束时引用仍然存在,但该对象将被删除。所以,这是错误的:

Vec& operator+(Vektor& a)
{
    Vec temp(*this);
    temp.x = this->x + a.x;
    temp.y = this->y + a.y;
    temp.z = this->z + a.z;
    return temp;
}

这是正确的:

Vec operator+(Vektor& a)
{
    Vec temp(*this);
    temp.x = this->x + a.x;
    temp.y = this->y + a.y;
    temp.z = this->z + a.z;
    return temp;
}

现在,我的问题是,如果我实际使用上层版本,为什么c的输出工作和结果的直接输出不是?我重载了<<操作员以及。第二个输出结果是乱码,如1.9492387e-12或其他东西。第一个输出(c)正确地给了我2,4和6。

Vec* a = new Vec(1, 2, 3);
Vec* b = new Vec(1, 2, 3);
Vec c = (*a + *b);

std::cout << c << std::endl << (*a + *b) << std::endl;

有什么想法吗? 这是重载的&lt;&lt;操作者:

friend std::ostream& operator<<(std::ostream& o, Vektor& a) {
    o << a.x << std::endl << a.y << std::endl << a.z << std::endl;

    return o;
}

另外,为什么我在这里返回对流的引用?

感谢。

2 个答案:

答案 0 :(得分:1)

这是未定义的行为:

Vec c = (*a + *b);

因为加法运算符返回对已失效对象的引用。它可能出现,但不能依赖。人们常说,当程序有未定义的行为时,字面意思任何都可能发生。这是夸大其词,但程序可能以不可预测的方式失败,并且似乎有时只能起作用。底线是它错了。

关于这个

std::ostream& operator<<(std::ostream& o, Vektor& a)

ostream通过引用返回,以便您可以链接它,例如

std::cout << Vektor(1, 2, 3) << " " << Vektor(4, 5, 6) << std::endl;

返回的引用是输入参数。

请注意,这里绝对没有理由使用动态分配:

Vec* a = new Vec(1, 2, 3);

您可以通过说

来简化事情
Vec a(1, 2, 3);

答案 1 :(得分:0)

在第一种情况下

Vec& operator+(Vec& a)
{
    Vec temp(*this);
    temp.x = this->x + a.x;
    temp.y = this->y + a.y;
    temp.z = this->z + a.z;
    return temp;
}

您正在创建一个临时对象“ temp ”并返回其引用。像RVO这样的优化没有太多优化,因为你明确要求引用那个特定的对象(它们不能发生)..并且在这个函数结束之后你将有一个对垃圾的引用。这是未定义的行为,您可能仍会得到正确的结果,但可能不会。至于“为什么c工作而直接计算没有”,它不可能知道先验,也许直接计算涉及某种临时值,立即被重用,因此你看到垃圾而第一个没有。

在第二种情况下,如您所述,您要求该对象的副本,从而接收具有复制值的该对象的副本在正确的地方。

我使用下面的代码(C ++ 11):

#include <iostream>
using namespace std;

class Vec {
public:
    Vec operator+(Vec& a)
    {
        Vec temp(*this);
        temp.x = this->x + a.x;
        temp.y = this->y + a.y;
        temp.z = this->z + a.z;
        return temp;
    }

    friend std::ostream& operator<<(std::ostream& o, Vec a) {
       o << a.x << std::endl << a.y << std::endl << a.z << std::endl;
       return o;
    }

    int x,y,z;
};



int main() {
    Vec* a = new Vec{1, 2, 3};
    Vec* b = new Vec{1, 2, 3};
    Vec c = (*a + *b);

    std::cout << c << std::endl << (*a + *b) << std::endl;

    return 0;
}

http://ideone.com/XANijy

请注意,友元函数中用于输出向量内容的引用是有效的,因为您返回的对象与您通过引用传递的对象相同并且功能完全正常(std::cout