C++ c++;自定义运算符(+;=)的行为方式不可预测

C++ c++;自定义运算符(+;=)的行为方式不可预测,c++,operator-keyword,C++,Operator Keyword,上面是名为Kvector的结构运算符的定义(带float x y z的结构,三个简单对象,仅此而已) 如果我对代码的理解正确,应打印以下代码29。它确实如此 Kvector::Kvector(float x, float y, float z) : x(x), y(y),z(z) {}; Kvector& Kvector::operator+(const Kvector& other) { return Kvector(x + other.x, y + other.y,

上面是名为Kvector的结构运算符的定义(带float x y z的结构,三个简单对象,仅此而已)

如果我对代码的理解正确,应打印以下代码29。它确实如此

Kvector::Kvector(float x, float y, float z) : x(x), y(y),z(z) {};

Kvector& Kvector::operator+(const Kvector& other) {
    return Kvector(x + other.x, y + other.y, z + other.z);
};

Kvector& Kvector::operator*(const Kvector& other) {
    return Kvector((x == 0) ? 0 : x*other.x, 
                   (y == 0) ? y * other.y : 0,
                   (z == 0) ? 0 : z * other.z);
};

Kvector& Kvector::operator*(const float other) {
    return Kvector(x * other, y * other, z * other);
};

void Kvector::operator+=(const Kvector& other) {
    x += other.x;
    y += other.y;
    z += other.z;
};
Kvector a(1,1,1);
a=a*29;
库特

返回对临时对象的引用。不对。在返回类型中将
Kvector&
替换为
Kvector

操作员+=签名为:

Kvector& Kvector::operator+(const Kvector& other){return Kvector    (x+other.x,y+other.y,z+other.z); };
Kvector& Kvector::operator*(const Kvector& other){return Kvector((x==0)?0: x*other.x,(y==0)?    y*other.y:0,(z== 0)? 0: z*other.z); };
Kvector& Kvector::operator*(const float other){return Kvector( x*other,y*other,z*other); };
实现+usign+=以减少代码重复并将其作为一个免费函数也是一个很好的实践

Kvector& Kvector::operator+=(const Kvector& other) 
{
  x+=other.x; 
  y+=other.y; 
  z +=other.z;

  return *this;
};

当前,您的代码正在返回Kvector&for运算符+,它返回对局部变量的引用,这显然是错误的。

您不应该在方法中返回局部变量作为引用。结果可能出乎意料。许多C++编译器应该警告你,比如VC++ 11

如果你使用MSVC++,首先要做的是项目设置,并要求编译器禁用所有的语言扩展。你的代码甚至不是有效的C++。从形式上讲,它是不可编译的。由于启用了扩展,编译器接受了它。在这种情况下,扩展导致代码根本不起作用。顺便问一下,在第一个操作符
*
中,在
x==0
(和
y==0
z==0
)上分支的意义是什么?为什么不在没有分支的情况下进行乘法呢?您的第二个运算符
*
没有为零进行分支。为什么第一个可以?我在分部工作。不知怎的,“不要偏离零”这个概念在我脑子里和乘法混在一起了。很抱歉。什么意思,我的代码甚至不是有效的C++?我认为我在C++中编写C++,把非CONT引用附加到临时对象是非法的。您的运算符
+
*
在其
返回
语句中正是这样做的。这是无效的、不可编译的。
+
可以作为
返回Kvector(a)+=b写在一行中,如果你喜欢的话。谢谢你的好技巧。我真的很感激。希望我能投票支持你的答案和所有其他人的努力,但我不能,因为我的声誉只有3。谢谢你。@AndreyT:但这可能不是那么理想,@Joelfalcu提供的形式是我投票的原因之一。它显式返回所做的复制,而不是
运算符+=
的结果。虽然这些应该是同一件事,但显式化使优化器更容易使用[N]RVO并消除临时性错误。当
op+=
的实现不是内联的时,显式尤其有帮助:如果
op+=
的实现没有返回对
*此
的引用,该怎么办?编译器无法从签名中辨别。只是一个nit,但它只是一个惯例,即
运算符+=
返回一个引用,而不是
void
。没有任何正式的要求。(当然,最好遵循这些既定的惯例。)@Charles Bailey:这要看情况。我想说NRVO比普通的RVO更具“异国情调”。谢谢你的建议。我会记住下次不要返回局部变量。
Kvector a(1,1,1);
a = a+ a*29;
cout<<"poss "<<a.x << " "<<a.y<< " "<< a.z<<endl;
Kvector& Kvector::operator+(const Kvector& other){return Kvector    (x+other.x,y+other.y,z+other.z); };
Kvector& Kvector::operator*(const Kvector& other){return Kvector((x==0)?0: x*other.x,(y==0)?    y*other.y:0,(z== 0)? 0: z*other.z); };
Kvector& Kvector::operator*(const float other){return Kvector( x*other,y*other,z*other); };
Kvector& Kvector::operator+=(const Kvector& other) 
{
  x+=other.x; 
  y+=other.y; 
  z +=other.z;

  return *this;
};
Kvector Kvector::operator+(const Kvector& a, const Kvector& b) 
{
  Kvector result(a);
  result += b;
  return result;
};