+= 运算符是如何在 C++ 中实现的?
How has += operator been implemented in c++?
这是一个我一直在思考的问题,但从未找到任何资源来说明这个问题的答案。事实上,它不仅适用于 +=
,还适用于它的兄弟姐妹,即 -=
、*=
、/=
等(当然不是 ==
)。
考虑这个例子,
int a = 5;
a += 4;
//this will make 'a' 9
现在考虑等效表达式:
a = a + 4;
//This also makes 'a' 9
如果 +=
只是 a = a + <rhs of +=>
的 shorthand
重载 + 运算符也应隐式重载 +=
,除非以其他方式显式重载。但事实并非如此。这意味着,a += b
不会转换为 a = a + b
。但为什么不以这种方式实施呢?就像在编译期间将其简单地转换为 a = a + b
而不是将其作为运算符单独实现本身不是更容易吗?这也有助于运算符重载,其中 a += b
,其中 a
和 b
是相同 class 的对象不必显式重载,只需重载 +
就够了吗?
编辑:
this answer
我的问题变得更清楚了
让我用一个需要重载运算符的例子来解释我的问题:
class A {
int ivar;
public:
A() = default;
A(int par_ivar) : ivar(par_ivar) { }
A(A& a) {
this.ivar = a.ivar;
}
A(A&& a) noexcept {
this.ivar = a.ivar;
}
A operator+(const A& a) const {
A temp_a;
temp_a.ivar = this.ivar + a.ivar;
return temp_a;
}
void operator=(const A& a) {
this.ivar = a.ivar;
}
~A() = default;
};
现在,让我们看一下 2 个程序的结果:
程序 1:
int main() {
A a1(2);
A a2(3);
a1 = a1 + a2; //a1.ivar = 5
return 0;
}
prog2:
int main() {
A a1(2);
A a2(3);
a1 += a2; //compilation error!!
return 0;
}
即使两个程序都打算做,不,做同样的事情,一个编译并运行(希望我的重载是正确的)另一个甚至不编译!!如果 += 被简单地替换为适当的 + 和 =,我们就不会觉得需要显式重载 +=。这是有意为之,还是等待添加的功能?
使用 a = a + b
将意味着使用 copy assignment(因为使用 operator =
)。另一方面,a += b
默认是复合赋值。
根据cppreference,
copy assignment operator replaces the contents of the object a with a copy of the contents of b (b is not modified).
和
compound assignment operators replace the contents of the object a with the result of a binary operation between the previous value of a and the value of b.
使用 a = a + b
,因此会导致不必要的内存使用,因为 a
在其值更改之前必须复制一次。
运算符不是由其他运算符生成的(C++20 中的 with/from <=> 除外):
提供 operator <
不允许 a > b
(实际上 "logically" 等同于 b < a
)。你必须实现所有(甚至通过重新使用一些)。
对于 类,a += b
不是 a = a + b
的 shorthand
但是 a.operator +=(b)
或 operator +=(a, b)
同样,a = a + b
是 a.operator=(operator +(a, b))
(或其变体)的 shorthand
在实践中,从 operator +=
实施 operator+
比反向实施更有效。
即使用户可能根据他们的名字期望类似的行为,它们也是常规函数。
我已经看到一个矩阵迭代器,它 ++it
增加列索引而 it++
增加行索引。
If +=
were simply a shorthand for a = a + <rhs of +=>
overloading + operator should also implicitly overload +=
, unless explicitly overloaded otherwise. But that isn't what happens. That means, a += b
doesn't get converted to a = a + b
.
(可能)不生成的原因可能是性能和控制:
向量(用于数学)或矩阵是很好的例子:
4 种可能的重载
Matrix operator+(Matrix&& lhs, Matrix&& rhs) { return std::move(lhs += rhs); }
Matrix operator+(Matrix&& lhs, const Matrix& rhs) { return std::move(lhs += rhs); }
Matrix operator+(const Matrix& lhs, Matrix&& rhs) { return std::move(rhs += lhs); } // + is symmetrical :)
Matrix operator+(const Matrix& lhs, const Matrix& rhs) { auto tmp{lhs}; return tmp += rhs; }
决定的副作用允许赋予运算符不同的含义,如 "name operator":
if (42 <in> std::vector{4, 8, 15, 16, 23, 42})
这是一个我一直在思考的问题,但从未找到任何资源来说明这个问题的答案。事实上,它不仅适用于 +=
,还适用于它的兄弟姐妹,即 -=
、*=
、/=
等(当然不是 ==
)。
考虑这个例子,
int a = 5;
a += 4;
//this will make 'a' 9
现在考虑等效表达式:
a = a + 4;
//This also makes 'a' 9
如果 +=
只是 a = a + <rhs of +=>
的 shorthand
重载 + 运算符也应隐式重载 +=
,除非以其他方式显式重载。但事实并非如此。这意味着,a += b
不会转换为 a = a + b
。但为什么不以这种方式实施呢?就像在编译期间将其简单地转换为 a = a + b
而不是将其作为运算符单独实现本身不是更容易吗?这也有助于运算符重载,其中 a += b
,其中 a
和 b
是相同 class 的对象不必显式重载,只需重载 +
就够了吗?
编辑:
this answer
我的问题变得更清楚了
让我用一个需要重载运算符的例子来解释我的问题:
class A {
int ivar;
public:
A() = default;
A(int par_ivar) : ivar(par_ivar) { }
A(A& a) {
this.ivar = a.ivar;
}
A(A&& a) noexcept {
this.ivar = a.ivar;
}
A operator+(const A& a) const {
A temp_a;
temp_a.ivar = this.ivar + a.ivar;
return temp_a;
}
void operator=(const A& a) {
this.ivar = a.ivar;
}
~A() = default;
};
现在,让我们看一下 2 个程序的结果:
程序 1:
int main() {
A a1(2);
A a2(3);
a1 = a1 + a2; //a1.ivar = 5
return 0;
}
prog2:
int main() {
A a1(2);
A a2(3);
a1 += a2; //compilation error!!
return 0;
}
即使两个程序都打算做,不,做同样的事情,一个编译并运行(希望我的重载是正确的)另一个甚至不编译!!如果 += 被简单地替换为适当的 + 和 =,我们就不会觉得需要显式重载 +=。这是有意为之,还是等待添加的功能?
使用 a = a + b
将意味着使用 copy assignment(因为使用 operator =
)。另一方面,a += b
默认是复合赋值。
根据cppreference,
copy assignment operator replaces the contents of the object a with a copy of the contents of b (b is not modified).
和
compound assignment operators replace the contents of the object a with the result of a binary operation between the previous value of a and the value of b.
使用 a = a + b
,因此会导致不必要的内存使用,因为 a
在其值更改之前必须复制一次。
运算符不是由其他运算符生成的(C++20 中的 with/from <=> 除外):
提供 operator <
不允许 a > b
(实际上 "logically" 等同于 b < a
)。你必须实现所有(甚至通过重新使用一些)。
对于 类,a += b
不是 a = a + b
但是 a.operator +=(b)
或 operator +=(a, b)
同样,a = a + b
是 a.operator=(operator +(a, b))
(或其变体)的 shorthand
在实践中,从 operator +=
实施 operator+
比反向实施更有效。
即使用户可能根据他们的名字期望类似的行为,它们也是常规函数。
我已经看到一个矩阵迭代器,它 ++it
增加列索引而 it++
增加行索引。
If
+=
were simply a shorthand fora = a + <rhs of +=>
overloading + operator should also implicitlyoverload +=
, unless explicitly overloaded otherwise. But that isn't what happens. That means,a += b
doesn't get converted toa = a + b
.
(可能)不生成的原因可能是性能和控制:
向量(用于数学)或矩阵是很好的例子:
4 种可能的重载
Matrix operator+(Matrix&& lhs, Matrix&& rhs) { return std::move(lhs += rhs); }
Matrix operator+(Matrix&& lhs, const Matrix& rhs) { return std::move(lhs += rhs); }
Matrix operator+(const Matrix& lhs, Matrix&& rhs) { return std::move(rhs += lhs); } // + is symmetrical :)
Matrix operator+(const Matrix& lhs, const Matrix& rhs) { auto tmp{lhs}; return tmp += rhs; }
决定的副作用允许赋予运算符不同的含义,如 "name operator":
if (42 <in> std::vector{4, 8, 15, 16, 23, 42})