由于复制省略,通常首选pass objects by value,只要保留内部副本即可。以下情况如何:
struct A
{
A(int x, int y) : x(x), y(y) {}
int x, y;
};
struct B
{
B(A a) : a(a) {} // 1
B(const A& a) : a(a) {} // 2
A a;
};
struct C : A
{
C(A a) : A(a) {} // 3
C(const A& a) : A(a) {} // 4
};
struct D : B, C
{
D(A a) : B(a), C(a) {} // 5
D(const A& a) : B(a), C(a) {} // 6
};
链接副本是否仍然被删除,即1,3和5更好?或者更确切地说是2,4,6?它取决于内联吗?
答案 0 :(得分:2)
在你的例子中,我认为它没有多大区别。 A
的构造函数没有副作用,因此标准关于复制省略的规则是无关紧要的。重要的是优化者可以实现的目标。一旦构造函数被内联,我希望在两种情况下大致相同,并且没有特别的理由说明为什么这个构造函数不能被内联(它很小并且它在类定义中定义)。
如果B
构造函数无法内联或A
构造函数有副作用,则必须复制到数据成员(C
中的基类子对象相同)和D
)。关于复制省略的标准规则不允许从参数到数据成员的复制被删除,因此在现实情况下,您将看到不需要的副本。
假设类型A
具有比复制更有效的移动构造函数,在调用者传递临时对象的情况下,以下是明显的胜利:
struct B
{
B(A a) : a(std::move(a)) {}
A a;
};
原因是这可以直接将临时构造到函数参数中,然后将其移动到数据成员中。 2/4/6不能(安全地)从左值引用到const移动到数据成员中。 1/3/5可以安全地移动,因为参数a
不再使用,但是不允许编译器为自己进行更改,除非(a)你赋予它std::move
的权限,或(b)它们在“as-if”规则下是等同的。
在调用者传递左值的情况下,我的构造函数可能比(2)略慢,因为我的构造函数复制然后移动,而(2)只是复制。您可以忽略此成本(因为移动应该非常便宜),或者您可以编写单独的const A&
和A&&
构造函数。我希望一般的经验法则是做前者。