是具有复制和交换习惯用法的复制赋值运算符,建议进行自赋值检查

Is copy assignment operator with copy and swap idiom and self assignment check recommended?

本文关键字:复制 检查 赋值 交换 习惯 惯用法 赋值运算符      更新时间:2023-10-16

在这里,您可以看到带有自分配检查的复制分配运算符实现:

String & operator=(const String & s)
{
    if (this != &s)
    {
        String(s).swap(*this); //Copy-constructor and non-throwing swap
    }
    // Old resources are released with the destruction of the temporary above
    return *this;
}

这有利于自我分配,但对性能不利:

  1. 因为每次它都像语句一样检查(考虑到分支预测,我不知道它的最佳程度是多少)
  2. 我们这里也失去了右值参数的省略

所以我仍然不明白如果我要实现std::vectoroperator=,我将如何实现它

是的,这段代码非常棒。的确,它正在造成额外的不必要的分支。有了适当的交换和移动语义,以下应该更具性能:

String& String::operator=(String s) { // note passing by value!
    std::swap(s, *this); // expected to juggle couple of pointers, will do nothing for self-assingment
    return *this;
}

还要注意的是,按价值接受论点更有益。

因为每次它都像语句一样检查(考虑到分支预测,我不知道它的最佳值是多少)

我认为你已经陷入了一个过早的优化圈。

检查自分配->如果代码写得正确,那么自分配是不必要的->如果你是认真的,为什么不显式地写swap?->我们回到了的原点

现实地说,我只想实现Allocator,而不必担心它

此外,我们在这里失去了对右值参数的复制省略

我不这么认为。

#include <iostream>
#define loud(x) std::cout << x << "n";
struct foo
{
    foo() { loud("default") }
    ~foo() { loud("destruct") }
    foo(const foo&) { loud("copy") }
    foo(foo&&) { loud("move") }
    foo & operator=(const foo & s)
    {
        if (this != &s)
        {
            loud("copy assign")
        }
        return *this;
    }
};
int main()
{
    foo f;
    foo g;
    g = f;
}

输出:

default
default
copy assign
destruct
destruct

这是-fno-elide-constructors


您声称分支可能有问题,但-O2的汇编输出向我表明,GCC甚至不发出operator=的代码,只是直接输出"copy assign"字符串。是的,我意识到我有一个简化的例子,但实际上是错误的起点。