C++添加2个3D向量将返回垃圾值



我对c++很陌生,刚刚开始学习运算符重载。这是我的尝试

class Vector
{
public:
float x=0,y=0,z=0;
Vector(float x, float y, float z) :x(x),y(y),z(z) {}
Vector(Vector& copy) :x(copy.x),y(copy.y),z(copy.z){ std::cout << "Copy Created" << std::endl;} //Testing if any new objects were created during the operator overloading process[For my purpose this should not be called as no new objects should be created except than the returned result of each operator]
public:
Vector& operator+(Vector& v1) //return this+v1
{
Vector v(this->x+v1.x,this->y+v1.y,this->z+v1.z);
return v;
}
Vector& operator-(Vector& v1) //return this-v1
{
Vector v(this->x - v1.x, this->y - v1.y, this->z - v1.z);
return v;
}
Vector& operator*(Vector& v1) //return this cross v1
{
Vector v(this->y * v1.z-this->z * v1.y, -this->x * v1.z + this->z * v1.x, this->x * v1.y - this->y * v1.x);
return v;
}
}
std::ostream& operator<<(std::ostream& output, Vector& v)  
{
output << v.x << "," << v.y << "," << v.z << std::endl;
return output;
}
int main()
{
Vector
v1(1, 2, 3),
v2(4, 5, 6);
Vector
v3 = v1 + v2,
v4 = v1 - v2,
v5 = v1 * v2;

std::cout << v3 << v4 << v5;
return 1;
}

打印时,所有3个矢量都具有垃圾值,并且每个操作调用复制构造函数3次。我已经通过引用传递了每个向量,但仍然在我不理解的地方创建了一个新的临时实例。

我还尝试过像以前的线程建议的那样,将关键字const添加到运算符及其参数中,但它并没有解决问题

由于我是一个新手,如果能详细解释一下解决方案,我将不胜感激。谢谢

运算符+*-通常返回一个副本而不是引用:

Vector operator+(const Vector& v1) const
//^^ no &
//^^ added const  
//^^ added const
{
Vector v(this->x+v1.x,this->y+v1.y,this->z+v1.z);
return v;
}

此外,您应该将该方法声明为const,这样您就可以在常量向量上调用operator+。该参数应作为const的参考。

有关运算符重载的更多详细信息,请参阅此处:运算符重载的基本规则和习惯用法是什么?

在您的代码中,您返回的是对一个局部变量的引用,而这个引用总是错误的。一个简化的例子是

int& foo() {
int x = 0;
return x;
}

当函数返回并且调用方获得悬空引用时,局部变量x的生命周期结束。使用该引用会调用未定义的行为。

如果确实要避免副本,则应重载复合运算符+=*=-=。他们应该就地执行操作,并且通常在修改this后返回对它的引用。有关详细信息,请参阅上面的链接。

我写了";应当"典型地";以及";传统上";在上面运算符重载相当灵活,可以做最奇怪的事情。然而,惯例是从运算符+*-返回一个新值,并且返回对局部变量的引用总是错误的。

最后但同样重要的是,我想提到的是,看到一个初学者代码应用了如此少的不良实践,这让人耳目一新。除了你的错误,我唯一会批评的是常量的正确性。默认情况下,将方法和参数设为const。只有当您需要修改它们时,才使它们成为常量。例如,你的operator<<也应该取一个const Vector&,因为它不会修改它

根据您的代码,我建议将您的运算符更改为运算符+=-=和*=。它们非常适合你的目的。在每次操作结束时,返回*this。这意味着返回当前工作对象。例如:

vector& vector::operator+= (const vector& v) 
{ this->x += v.x;
this->y += v.y;
this->z += v.z;
return *this; 
}

和写运算符+作为两个参数的朋友函数:

vector operator+(const vector&v1, const vector&v2)
{ vector v3(v1);  // copy constructor
v3 += v2;
return v3;
}

不确定,但我认为你得到垃圾值是因为你试图返回对本地堆栈值v的引用。在你重载运算符的作用域结束后,'v'值可能会被程序的另一部分覆盖。

可能的解决方案是:

Vector& operator+(Vector& v1) //return this+v1
{
return *new Vector(this->x+v1.x,this->y+v1.y,this->z+v1.z);
}

最新更新