引用与对象作为运算符重载中的返回

References vs Objects as returns in operator overloads

本文关键字:重载 返回 运算符 对象 引用      更新时间:2023-10-16

我正在试图重载C++中的binary+运算符。现在,我发现重载运算符时返回对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的输出有效,而结果的直接输出无效?我使<lt;操作员。第二个输出结果是胡言乱语,比如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;操作员:

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

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

谢谢。

这是未定义的行为:

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);

在第一种情况下,

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)