显式复制构造函数或隐式参数值

时间:2010-01-09 19:29:26

标签: c++ optimization parameters operators conversion-operator

我最近阅读(并且遗憾地忘记了哪里),编写operator =的最佳方法是这样的:

foo &operator=(foo other)
{
    swap(*this, other);
    return *this;
}

而不是:

foo &operator=(const foo &other)
{
    foo copy(other);
    swap(*this, copy);
    return *this;
}

这个想法是,如果使用rvalue调用operator =,则第一个版本可以优化复制的构造。因此,当使用rvalue调用时,第一个版本更快,当使用左值调用时,这两个版本是等效的。

我很好奇其他人对此的看法?由于缺乏明确性,人们会避免使用第一个版本吗?我是否正确,第一个版本可以更好,永远不会更糟?

5 个答案:

答案 0 :(得分:4)

您可能会从以下网址阅读:http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

我没有太多话要说,因为我觉得这个链接很好地解释了这个理由。有趣的是,我可以确认第一个表单在使用MSVC的构建中产生的副本更少,这是有道理的,因为编译器可能无法在第二个表单上执行copy-elision。我同意第一种形式是严格的改进,并且永远不会比第二种形式更差。

编辑: 第一种形式可能不那么惯用,但我认为它不太清楚。 (IMO,这并不比第一次看到赋值运算符的复制和交换实现更令人惊讶。)

编辑#2:哎呀,我打算写copy-elision,而不是RVO。

答案 1 :(得分:2)

我通常更倾向于从可读性和“最不惊讶”的角度来看第二个,但是我确实认为当参数是临时的时,第一个可以更有效。

第一个真的可以导致 no 副本,而不仅仅是单个副本,并且可以想象在极端情况下这可能是一个真正的问题。

E.g。参加这个测试计划。 gcc -O3 -S(gcc版本4.4.2 20091222(Red Hat 4.4.2-20)(GCC))生成对B的复制构造函数的一次调用,但没有调用函数f的A的复制构造函数(赋值)运算符内联AB)。 AB都可以被视为非常基本的字符串类。 data的分配和复制将在构造函数中发生,并在析构函数中释放。

#include <algorithm>

class A
{
public:
    explicit A(const char*);
    A& operator=(A val)      { swap(val); return *this; }
    void swap(A& other)      { std::swap(data, other.data); }
    A(const A&);
    ~A();

private:
    const char* data;
};

class B
{
public:
    explicit B(const char*);
    B& operator=(const B& val)  { B tmp(val); swap(tmp); return *this; }
    void swap(B& other)         { std::swap(data, other.data); }
    B(const B&);
    ~B();

private:
    const char* data;
};

void f(A& a, B& b)
{
    a = A("Hello");
    b = B("World");
}

答案 2 :(得分:0)

鉴于此

foo &foo::operator=(foo other) {/*...*/ return *this;}
foo f();
像这样的代码中的

foo bar;
bar = f();

编译器可能更容易消除对复制构造函数的调用。使用RVO,它可以使用运算符的other参数的地址作为f()构造其返回值的位置。

似乎这种优化对于第二种情况也是可能的,尽管我认为它可能更难。 (特别是当操作员没有内联时。)

答案 3 :(得分:-2)

这两个实际上是一样的。唯一的区别是你在调试器中按“Step In”。你应该提前知道在哪里做。

答案 4 :(得分:-3)

我认为你可能会混淆:

之间的区别

foo &operator=(const foo &other);
const foo &operator=(const foo &other);

第一个表格应该用于: (a = b) = c;