首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >要使用的:移动赋值运算符与复制赋值运算符

要使用的:移动赋值运算符与复制赋值运算符
EN

Stack Overflow用户
提问于 2014-11-06 05:10:52
回答 2查看 10.9K关注 0票数 11

我好像不明白你为什么要用move assignment operator

代码语言:javascript
复制
CLASSA & operator=(CLASSA && other); //move assignment operator

完毕,copy assignment operator

代码语言:javascript
复制
CLASSA & operator=(CLASSA  other); //copy assignment operator

move assignment operator只接受一个r-value reference

代码语言:javascript
复制
CLASSA a1, a2, a3;
a1 = a2 + a3;

copy assignment operator中,other可以是使用copy constructormove constructor的构造函数(如果other是用rvalue初始化的,则可以移动-构造--如果定义了move-constructor )。

如果是copy-constructed,我们将执行1次复制,而该副本是无法避免的。

如果是move-constructed,那么其性能/行为与第一个重载所产生的性能/行为相同。

我的问题是:

1-为什么要实现move assignment operator

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-11-06 08:52:37

你不是在跟我比

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

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

  1. T& operator=(T const&)
  2. T& operator=(T const&)T& operator=(T&&)
  3. T& operator=(T)与移动

请注意,您在一个类中建议的这两个重载都不是一个选项,因为它是不明确的。

选项1是传统的C++98选项,在大多数情况下执行得很好。但是,如果您需要优化r值,您可以考虑选项2并添加一个移动赋值操作符。

这是诱人的考虑选项3和传递的价值,然后移动,我认为这是你的建议。在这种情况下,您只需编写一个赋值运算符。它接受l-值,只需额外移动一次就可以接受r-值,许多人都会提倡这种方法。

然而,Herb在2014年的“回到基础!现代C++风格的要点”演讲中指出,这一选择是有问题的,而且可能会慢得多。在l-值的情况下,它将执行一个无条件的副本,不会重用任何现有的容量。他提供数字来支持他的主张。唯一的例外是没有可重用的现有能力的构造函数,而且您通常有许多参数,因此传递值可以减少所需的重载数。

因此,我建议您从选项1开始,如果需要优化r值,则移到选项2。

票数 11
EN

Stack Overflow用户

发布于 2014-11-06 06:10:42

显然,这两种超载并不等同:

  1. 接受rvalue引用的赋值运算符仅适用于表达式右侧的rvalue。为了支持lvalue,还需要对可复制类型使用另一个重载(例如,使用T const& )。当然,对于只移动的类型,比如std::unique_ptr<T>,定义这个赋值运算符是合适的选择.
  2. 接受值的赋值操作符包含rvalue和lvalue赋值,假设所讨论的类型都是可复制的和可移动的。它的规范实现是调用swap()将对象的状态从右侧替换为状态。它的优点是,参数的复制/移动结构常常可以被省略。

在任何情况下,您都不希望两个重载都在一个类中!显然,当从lvalue赋值时,会选择使用值的版本(另一个选项不可行)。然而,在分配rvalue时,这两种赋值运算符都是可行的,也就是说,将出现模糊。通过尝试编译以下代码,可以很容易地验证这一点:

代码语言:javascript
复制
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)
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26772146

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档