使用哪种:移动分配运算符与复制分配运算符
Which to use: move assignment operator vs copy assignment operator
我似乎不明白为什么要使用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
是用右值初始化的,那么它可以是移动构造的——如果定义了move-constructor
——)。
如果是copy-constructed
,我们将进行1次复制,该复制无法避免。
如果是move-constructed
,则性能/行为与第一次过载产生的性能/行为相同。
我的问题是:
1-为什么要实现move assignment operator
。
2-如果other
是由r值构造的,那么编译器会选择调用哪个assignment operator
?为什么?
您不是在比较同类
如果您正在编写像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在2014年CppCon的"回归基础!现代C++风格的要点"演讲中指出,这种选择是有问题的,而且可能会慢得多。在l值的情况下,它将执行无条件复制,并且不会重用任何现有容量。他提供了数字来支持他的说法。唯一的例外是构造函数,那里没有可重用的现有容量,并且您通常有许多参数,因此传递值可以减少所需的重载次数。
因此,如果需要优化r值,我建议您从选项1开始,然后转到选项2。
显然,这两个重载是不等价的:
- 接受右值引用的赋值运算符仅适用于表达式右侧的右值。为了支持lvalues,对于可复制类型,还需要另一个重载,例如使用
T const&
。当然,对于仅移动类型(如std::unique_ptr<T>
),定义此赋值运算符是合适的选择 - 假定所讨论的类型是可复制和可移动构造的,则取值的赋值运算符涵盖了右值和左值赋值。它的规范实现是调用
swap()
,用右侧的状态替换对象的状态。它的优点是,论点的复制/移动结构通常可以被忽略
无论如何,您都不希望在一个类中同时包含两个重载!当从左值赋值时,显然会选择采用值的版本(另一个选项不可行)。然而,当分配右值时,两个赋值运算符都是可行的,即,会有歧义。这可以很容易地通过尝试编译以下代码来验证:
struct foo
{
void operator=(foo&&) {}
void operator=(foo) {}
};
int main()
{
foo f;
f = foo();
}
要分别处理移动和复制构造,可以使用T&&
和T const&
作为参数定义一对赋值运算符。然而,这导致必须实现两个版本的基本相同的复制分配,而只有一个T
作为参数只需要实现一个复制分配。
因此,有两个明显的选择:
- 对于只移动类型,您可以定义
T::operator= (T&&)
- 对于可复制类型,您可以定义
T::operator=(T)
- 正在尝试重载二进制搜索树分配运算符
- 自定义先决条件对移动分配运算符有效吗
- C++ - 没有自定义交换功能的移动分配运算符?
- 强制复制分配超过移动分配运算符
- 在之后仍需要使用源对象时调用父移动分配运算符
- c++ 使用动态分配运算符反向数组元素
- 当存在用户定义的移动分配运算符时,已删除模板移动分配运算符
- C++ - 从移动分配运算符调用复制分配
- 不工作 复制分配运算符
- =删除用户定义的成员功能,除了构造函数,分配运算符C 11
- 返回对象如何与分配运算符一起工作
- 下标是否在分配运算符的右侧进行评估
- C++分配适用于已删除的分配运算符
- 用于删除复制/移动分配运算符的有效签名
- 使用新放置作为复制分配运算符不好吗?
- C++ - 父级中的 CRTP 分配运算符不起作用
- 复制派生类的分配运算符
- 未定义 Lambda 复制分配运算符
- 为什么标准在移动分配运算符中使用交换?
- 正确编写复制构造函数和分配运算符的方法