【问题标题】:Pass by value vs. pass by reference in copy assignment operator在复制赋值运算符中按值传递与按引用传递
【发布时间】:2020-06-12 02:39:02
【问题描述】:

首先,有一个类似的热门帖子What is the copy-and-swap idiom?。 接受的答案有一个指向https://web.archive.org/web/20140113221447/http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/的链接。

复制赋值运算符的常用实现是已接受和链接的页面状态(从上一个链接复制和粘贴)

T& T::operator=(T const& x) // x is a reference to the source
{ 
    T tmp(x);          // copy construction of tmp does the hard work
    swap(*this, tmp);  // trade our resources for tmp's
    return *this;      // our (old) resources get destroyed with tmp 
}

但是

T& operator=(T x)    // x is a copy of the source; hard work already done
{
    swap(*this, x);  // trade our resources for x's
    return *this;    // our (old) resources get destroyed with x
}

由于编译器的复制省略优化而更好,或者通常,总是按值传递而不是按引用传递,然后复制按引用传递的参数。

我同意第二个选项与第一个选项相同或更好,但并不差,但我很困惑为什么第一个选项一开始就是这样写的。我不明白为什么需要临时变量和交换。

相反,我们就不能这样做:

T& T::operator=(T const& x) // x is a reference to the source
{ 
    this->member_var = x.member_var;
    //if we have to do a deep copy of something, implement that here
    return *this;
}

不使用复制构造函数。

【问题讨论】:

  • @JerryJeremiah 这完全取决于复制构造函数的实现方式......复制/交换不会强制浅复制。
  • 您对我们使用复制/交换的原因及其成本是正确的。不需要复制/交换,它不会自动成为更好的解决方案。但它非常有用。您可能从链接的问题中错过的一个好处是异常安全。使用复制/交换,分配成功或this 不变。 swap 应始终为 noexcept,因此只有副本才能失败。如果是这样,swap 永远不会发生。这样做几乎总是有一点开销,而且使用复制/交换的开销并没有太大的不同。
  • 当您调用operator= 时,如果您传递的对象是一个右值,那么参数x 将被移动构造。例如,在foo = std::move(bar) 中,foo::operator=(foo x) 中的参数x 是从bar 构造的移动。然后x 将与*this 交换。但是x 在这种情况下我们永远不会产生右值,只有std::move(bar) 会产生右值引用。
  • x 是一个左值表达式,就像任何其他命名变量一样。它有一个名称 (x),您可以获取它的地址 (&x)。它的构造方式不会改变它的价值类别。
  • 诀窍是值类别适用于表达式,而不是它们包含或表示的值。如果您有T x;,那么x 是一个左值。如果您有T function();,则调用函数结果是一个右值。如果你做了x = function();,那么function() 仍然返回一个右值,x 仍然是一个左值,即使它们现在代表相同的状态。

标签: c++ copy-assignment copy-and-swap


【解决方案1】:

如果有多个成员,您的赋值运算符不是异常安全的:

T& T::operator=(T const& x) 
{ 
    this->member_var1 = x.member_var1; 
    this->member_var2 = x.member_var2; // if an exception occurs here, this->member_var1 will still be changed
    return *this;
}

【讨论】:

  • 这与线程安全无关(没有同步,多成员交换也不是神奇的“安全”;几乎任何在没有同步或原子的情况下读取数据的尝试都可以读取垃圾,尤其是在具有弱有序的内存模型,或者由于撕裂),这是关于强异常保证的。
猜你喜欢
  • 2016-12-13
  • 1970-01-01
  • 2016-10-22
  • 2014-09-10
  • 2023-03-02
  • 2012-07-03
  • 1970-01-01
相关资源
最近更新 更多