C++ 添加 2 个 3D 向量 returns 垃圾值
C++ adding 2 3D vectors returns garbage value
我是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 添加到运算符及其参数,但它没有解决问题
由于我是新手,因此将不胜感激对解决方案的详尽解释。谢谢
不确定,但我认为你得到垃圾值是因为你试图 return 引用本地堆栈值 v。在你重载运算符的范围结束后,'v' 值可能会被另一个覆盖程序的一部分。
可能的解决方案是:
Vector& operator+(Vector& v1) //return this+v1
{
return *new Vector(this->x+v1.x,this->y+v1.y,this->z+v1.z);
}
运算符 +
、*
和 -
通常 return 复制而非参考:
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
参考。
有关运算符重载的更多详细信息,请参见此处:What are the basic rules and idioms for operator overloading?
在您的代码中,您return引用了一个总是错误的局部变量。一个简化的例子是
int& foo() {
int x = 0;
return x;
}
局部变量 x
的生命周期在函数 returns 和调用者获得悬空引用时结束。使用该引用调用 undefined behavior.
如果您确实想避免复制,您应该重载复合运算符 +=
、*=
、-=
。他们应该执行 in-place 操作,通常 return 在修改后引用 this
。详情见上文link.
我在上面写了“应该”、“通常”和“通常”。运算符重载相当灵活,可以做最奇怪的事情。但是,惯例是 return 来自运算符 +
、*
和 -
的新值,并且 return 对局部变量的引用总是错误的。
最后但并非最不重要的一点是,我想提一下,看到初学者代码应用了如此少的不良做法令人耳目一新。除了你的错误,我唯一要批评的是 const 正确性。默认情况下使方法和参数const
。仅当您需要修改它们时才使它们 non-const。例如,您的 operator<<
也应该采用 const Vector&
,因为它不会对其进行修改。
根据您的代码,我建议您将运算符更改为运算符+= -= 和 *=。它们非常适合您的目的。在每次操作结束时,return *this。意思是returning当前工作对象。例如:
vector& vector::operator+= (const vector& v)
{ this->x += v.x;
this->y += v.y;
this->z += v.z;
return *this;
}
并将 operator+ 编写为两个参数的友元函数:
vector operator+(const vector&v1, const vector&v2)
{ vector v3(v1); // copy constructor
v3 += v2;
return v3;
}
我是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 添加到运算符及其参数,但它没有解决问题
由于我是新手,因此将不胜感激对解决方案的详尽解释。谢谢
不确定,但我认为你得到垃圾值是因为你试图 return 引用本地堆栈值 v。在你重载运算符的范围结束后,'v' 值可能会被另一个覆盖程序的一部分。
可能的解决方案是:
Vector& operator+(Vector& v1) //return this+v1
{
return *new Vector(this->x+v1.x,this->y+v1.y,this->z+v1.z);
}
运算符 +
、*
和 -
通常 return 复制而非参考:
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
参考。
有关运算符重载的更多详细信息,请参见此处:What are the basic rules and idioms for operator overloading?
在您的代码中,您return引用了一个总是错误的局部变量。一个简化的例子是
int& foo() {
int x = 0;
return x;
}
局部变量 x
的生命周期在函数 returns 和调用者获得悬空引用时结束。使用该引用调用 undefined behavior.
如果您确实想避免复制,您应该重载复合运算符 +=
、*=
、-=
。他们应该执行 in-place 操作,通常 return 在修改后引用 this
。详情见上文link.
我在上面写了“应该”、“通常”和“通常”。运算符重载相当灵活,可以做最奇怪的事情。但是,惯例是 return 来自运算符 +
、*
和 -
的新值,并且 return 对局部变量的引用总是错误的。
最后但并非最不重要的一点是,我想提一下,看到初学者代码应用了如此少的不良做法令人耳目一新。除了你的错误,我唯一要批评的是 const 正确性。默认情况下使方法和参数const
。仅当您需要修改它们时才使它们 non-const。例如,您的 operator<<
也应该采用 const Vector&
,因为它不会对其进行修改。
根据您的代码,我建议您将运算符更改为运算符+= -= 和 *=。它们非常适合您的目的。在每次操作结束时,return *this。意思是returning当前工作对象。例如:
vector& vector::operator+= (const vector& v)
{ this->x += v.x;
this->y += v.y;
this->z += v.z;
return *this;
}
并将 operator+ 编写为两个参数的友元函数:
vector operator+(const vector&v1, const vector&v2)
{ vector v3(v1); // copy constructor
v3 += v2;
return v3;
}