我似乎不明白你为什么要使用move assignment operator
:
CLASSA & operator=(CLASSA && other); //move assignment operator
结束,copy assignment operator
:
CLASSA & operator=(CLASSA other); //copy assignment operator
move assignment operator
只需要r-value reference
,例如
CLASSA a1, a2, a3;
a1 = a2 + a3;
在copy assignment operator
中,other
可以是使用copy constructor
或move constructor
的构造函数(如果使用右值初始化other
,则可以移动-constructed --if move-constructor
定义 - )。
如果是copy-constructed
,我们将执行1份副本,并且无法避免该副本。
如果是move-constructed
,则性能/行为与第一次重载产生的性能/行为相同。
我的问题是:
1-为什么要实施move assignment operator
。
2-如果other
是由r值构成的,那么编译器会选择调用哪个assignment operator
?为什么?
答案 0 :(得分:6)
你没有比较喜欢与
相似如果您正在编写像std::unique_ptr
这样的仅限移动类型,那么移动赋值运算符将是您唯一的选择。
更典型的情况是你有一个可复制的类型,在这种情况下我认为你有三个选择。
T& operator=(T const&)
T& operator=(T const&)
和T& operator=(T&&)
T& operator=(T)
并移动请注意,在一个类中建议的重载都不是一个选项,因为它不明确。
选项1是传统的C ++ 98选项,在大多数情况下都可以正常运行。但是,如果需要针对r值进行优化,可以考虑选项2并添加移动赋值运算符。
很容易考虑选项3和按价值传递,然后移动我认为是你的建议。在这种情况下,您只需编写一个赋值运算符。它接受l值并且仅以一个额外的移动为代价接受r值,并且许多人将提倡这种方法。
然而,Herb Sutter在CppCon 2014的"Back to the Basics! Essentials of Modern C++ Style"演讲中指出,这个选项存在问题,可能会慢得多。在l值的情况下,它将执行无条件复制,并且不会重用任何现有容量。他提供数字来备份他的说法。唯一的例外是构造函数,其中没有现有的重用容量,并且您经常有许多参数,因此传递值可以减少所需的重载次数。
因此,我建议您从选项1开始,如果需要针对r值进行优化,请转到选项2。
答案 1 :(得分:2)
显然,两个重载不等同:
T const&
。当然,对于仅移动类型,例如std::unique_ptr<T>
,定义此赋值运算符是合适的选择。swap()
以从右侧的状态替换对象的状态。它的优点是通常可以省略参数的复制/移动构造。在任何情况下,您都不希望在一个类中同时拥有两个重载!显然,当从左值分配时,将选择采用值的版本(另一个选项是不可行的)。但是,在分配rvalue时,两个赋值运算符都是可行的,即,存在歧义。这可以通过尝试编译此代码轻松验证:
struct foo
{
void operator=(foo&&) {}
void operator=(foo) {}
};
int main()
{
foo f;
f = foo();
}
要单独处理移动和复制构造,您可以使用T&&
和T const&
作为参数定义一对赋值运算符。但是,这导致必须实现两个版本基本相同的复制赋值,而只有T
因为参数只需要实现一个复制赋值。
因此,有两个明显的选择:
T::operator= (T&&)
。T::operator=(T)
。