显式复制构造函数或按值隐式参数
我最近读到(不幸的是忘记在哪里),编写operator=的最佳方法是这样的:
foo &operator=(foo other)
{
swap(*this, other);
return *this;
}
而不是这样:
foo &operator=(const foo &other)
{
foo copy(other);
swap(*this, copy);
return *this;
}
这个想法是,如果使用右值调用operator=,第一个版本可以优化副本的构造。因此,当使用右值调用时,第一个版本更快,而当使用左值调用时,两个版本是等效的。
我很好奇其他人对此有何看法?人们会因为缺乏明确性而避免使用第一个版本吗?我是否正确地认为第一个版本可以更好并且永远不会更差?
I recently read (and unfortunately forgot where), that the best way to write operator= is like this:
foo &operator=(foo other)
{
swap(*this, other);
return *this;
}
instead of this:
foo &operator=(const foo &other)
{
foo copy(other);
swap(*this, copy);
return *this;
}
The idea is that if operator= is called with an rvalue, the first version can optimize away construction of a copy. So when called with a rvalue, the first version is faster and when called with an lvalue the two are equivalent.
I'm curious as to what other people think about this? Would people avoid the first version because of lack of explicitness? Am I correct that the first version can be better and can never be worse?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(5)
从可读性和“最少惊喜”的角度来看,我通常更喜欢第二个,但是我确实承认,当参数是临时参数时,第一个可以更有效。
第一个确实可能导致无副本,而不仅仅是单个副本,可以想象,这在极端情况下可能是一个真正的问题。
例如,采用这个测试程序。 gcc -O3 -S
(gcc 版本 4.4.2 20091222 (Red Hat 4.4.2-20) (GCC))生成一次对 B 的复制构造函数的调用,但不会调用 A 的函数复制构造函数 < code>f (A
和 B
都内联赋值运算符)。 A
和 B
都可以被视为非常基本的字符串类。数据的分配和复制将发生在构造函数中,而释放将发生在析构函数中。
#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");
}
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
您可能从以下位置阅读: http://cpp -next.com/archive/2009/08/want-speed-pass-by-value/
我没有太多要说的,因为我认为该链接很好地解释了原理。有趣的是,我可以确认第一种形式会导致我使用 MSVC 构建的副本较少,这是有道理的,因为编译器可能无法对第二种形式进行复制消除。我同意第一种形式是严格的改进,并且绝不会比第二种更差。
编辑:
第一种形式可能不太惯用,但我认为它并不太不清楚。 (IMO,这并不比第一次看到赋值运算符的复制和交换实现更令人惊讶。)
编辑#2:哎呀,我的意思是写复制省略,而不是 RVO。
You probably read it from: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
I don't have much to say since I think the link explains the rationale pretty well. Anecdotally I can confirm that the first form results in fewer copies in my builds with MSVC, which makes sense since compilers might not be able to do copy-elision on the second form. I agree that the first form is a strict improvement and is never worse than the second.
Edit:
The first form might be a bit less idiomatic, but I don't think it's much less clear. (IMO, it's not any more surprising than seeing the copy-and-swap implementation of the assignment operator for the first time.)
Edit #2: Oops, I meant to write copy-elision, not RVO.