使用哪个:移动赋值运算符与复制赋值运算符

时间:2014-11-06 05:10:52

标签: c++ c++11 overload-resolution

我似乎不明白你为什么要使用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 constructormove constructor的构造函数(如果使用右值初始化other,则可以移动-constructed --if move-constructor定义 - )。

如果是copy-constructed,我们将执行1份副本,并且无法避免该副本。

如果是move-constructed,则性能/行为与第一次重载产生的性能/行为相同。

我的问题是:

1-为什么要实施move assignment operator

2-如果other是由r值构成的,那么编译器会选择调用哪个assignment operator?为什么?

2 个答案:

答案 0 :(得分:6)

你没有比较喜欢与

相似

如果您正在编写像std::unique_ptr这样的仅限移动类型,那么移动赋值运算符将是您唯一的选择。

更典型的情况是你有一个可复制的类型,在这种情况下我认为你有三个选择。

  1. T& operator=(T const&)
  2. T& operator=(T const&)T& operator=(T&&)
  3. T& operator=(T)并移动
  4. 请注意,在一个类中建议的重载都不是一个选项,因为它不明确。

    选项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)

显然,两个重载不等同:

  1. 采用右值参考的赋值运算符仅适用于表达式右侧的右值。为了也支持左值,可复制类型需要另一个重载,例如使用T const&。当然,对于仅移动类型,例如std::unique_ptr<T>,定义此赋值运算符是合适的选择。
  2. 赋值的赋值运算符包括rvalue和lvalue赋值,假设所讨论的类型是复制和移动构造的。它的规范实现是调用swap()以从右侧的状态替换对象的状态。它的优点是通常可以省略参数的复制/移动构造。
  3. 在任何情况下,您都不希望在一个类中同时拥有两个重载!显然,当从左值分配时,将选择采用值的版本(另一个选项是不可行的)。但是,在分配rvalue时,两个赋值运算符都是可行的,即,存在歧义。这可以通过尝试编译此代码轻松验证:

    struct foo
    {
        void operator=(foo&&) {}
        void operator=(foo) {}
    };
    
    int main()
    {
        foo f;
        f = foo();
    }
    

    要单独处理移动和复制构造,您可以使用T&&T const&作为参数定义一对赋值运算符。但是,这导致必须实现两个版本基本相同的复制赋值,而只有T因为参数只需要实现一个复制赋值。

    因此,有两个明显的选择:

    1. 对于仅限移动类型,您可以定义T::operator= (T&&)
    2. 对于可复制类型,您可以定义T::operator=(T)