Xir*_*ema 10 c++ undefined-behavior move-semantics c++11
对于上下文,我正在使用的实际类比我在这里展示的更复杂和更大,但我只是作为一个例子使用它.
struct Vector {
int x, y;
Vector() : Vector(0,0) {}
Vector(int x, int y) : x(x), y(y) {}
};
Run Code Online (Sandbox Code Playgroud)
我想添加运算符重载以允许Vectors相互相加和相减.
Vector& operator+=(Vector const& v) {
x += v.x;
y += v.y;
return *this;
}
Vector operator+(Vector const& v) const {
return Vector(*this) += v;
}
Vector& operator-=(Vector const& v) {
x -= v.x;
y -= v.y;
return *this;
}
Vector operator-(Vector const& v) const {
return Vector(*this) -= v;
}
Run Code Online (Sandbox Code Playgroud)
但是,此代码可以允许不幸的结构:
int main() {
Vector & a = Vector(1,2) += Vector(5,4);//This compiles and invokes undefined behavior!
std::cout << a.x << ',' << a.y << std::endl;//This isn't safe!
}
Run Code Online (Sandbox Code Playgroud)
所以我重写了代码,要注意对象是L值还是R值:
Vector& operator+=(Vector const& v) & {
x += v.x;
y += v.y;
return *this;
}
Vector&& operator+=(Vector const& v) && {
return std::move(*this += v);
}
Vector operator+(Vector const& v) const {
return Vector(*this) += v;
}
Vector& operator-=(Vector const& v) & {
x -= v.x;
y -= v.y;
return *this;
}
Vector&& operator-=(Vector const& v) && {
return std::move(*this -= v);
}
Vector operator-(Vector const& v) const {
return Vector(*this) -= v;
}
Run Code Online (Sandbox Code Playgroud)
所以我剩下的问题是,即使这段代码编译并完成了我所期望的,这段代码是否安全并且没有意外的未定义行为?
int main() {
//No Longer compiles, good.
//Vector & a = Vector(1,2) += Vector(5,4);
//Is this safe?
Vector b = Vector(1,2) += Vector(5,4);
//Other cases where this code could be unsafe?
}
Run Code Online (Sandbox Code Playgroud)
以下是重载这些运算符的相对标准方法:
Vector& operator+=(Vector const& v)& {
x += v.x;
y += v.y;
return *this;
}
friend Vector operator+(Vector lhs, Vector const& v) {
lhs+=v;
return std::move(lhs); // move is redundant yet harmless in this case
}
Vector& operator-=(Vector const& v)& {
x -= v.x;
y -= v.y;
return *this;
}
friend Vector operator-(Vector lhs, Vector const& v) {
lhs -= v;
return std::move(lhs); // move is redundant yet harmless in this case
}
Run Code Online (Sandbox Code Playgroud)
请注意,在许多行上,+或者-上面生成的副本比重载更少.
a+b+c变为(a+b)+c,并且返回值a+b直接被省略到lhs参数中+c.你的第一行+无论如何都要创建一个副本,所以签名中的额外副本是无害的.
除非你有充分的理由,禁止+=和=rvalues. int不支持它,你也不应该支持它.