5

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

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. 就像每次检查 if 语句时一样(考虑到分支预测,我不知道它会优化多少)
  2. 我们也在这里丢失了右值参数的复制省略

所以我仍然不明白我是否会实施std::vector'operator=我将如何实施它。

4

2 回答 2

5

是的,这段代码是多余的。确实,它导致了额外的不必要的分支。使用适当的交换和移动语义,以下性能应该更高:

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;
}

另请注意,按值接受参数更有益。

于 2016-05-09T20:55:48.220 回答
1

就像每次检查 if 语句时一样(考虑到分支预测,我不知道它会优化多少)

我认为您在这里陷入了一个过早的优化圈。

检查自分配 -> 如果您正确编写代码,则不需要自分配 -> 如果您是认真的,为什么不swap明确写呢?-> 我们回到第一方

实际上,我只会实现分配器而不用担心它。

我们也在这里丢失了右值参数的复制省略

我不这么认为。

#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"直接输出字符串。是的,我意识到我有一个简化的例子,但它确实是从错误的一端开始。

于 2016-05-09T22:16:26.877 回答