我已经问了一些与这个问题有关的问题,但是得到的回答不一,所以我认为最好直接问。
假设我们有以下代码:
// Silly examples of A and B, don't take so seriously,
// just keep in mind they're big and not dynamically allocated.
struct A { int x[1000]; A() { for (int i = 0; i != 1000; ++i) { x[i] = i * 2; } };
struct B { int y[1000]; B() { for (int i = 0; i != 1000; ++i) { y[i] = i * 3; } };
struct C
{
A a;
B b;
};
A create_a() { return A(); }
B create_b() { return B(); }
C create_c(A&& a, B&& b)
{
C c;
c.a = std::move(a);
c.b = std::move(b);
return C;
};
int main()
{
C x = create_c(create_a(), create_b());
}
现在理想情况下,
create_c(A&&, B&&)
应该是一个空操作。A和B不应该在栈上创建并传递它们的引用,而是应该直接按值创建并传递到返回值c
的位置。使用NRVO,这将意味着直接创建并将它们传递到x
中,函数create_c
不需要再做任何额外的工作。
这将避免创建A和B的副本。
是否有任何方法可以让编译器允许/鼓励/强制执行此行为?或者优化编译器通常会自动执行此操作吗?这只有在编译器内联函数时才起作用,还是跨编译单元也能起作用?
(我认为这可能会跨编译单元工作...)
如果create_a()
和create_b()
带有一个隐藏参数来放置返回值,则它们可以直接将结果放入x
中,然后通过引用传递给create_c()
,后者无需进行任何操作即可立即返回。
create_c
并执行C c = { create_a(), create_b() };
,您现在就可以基本上获得相同的结果,而无需等待以后重构类型A
和B
。如果编译器进行了内联,那甚至可能已经是这种情况了。语义已经足够清晰,不需要rvalue-references,而且一个好的老编译器(实现当前标准)现在已经可以通过内联优化所有副本(通过内联)。 - David Rodríguez - dribeasA
和B
都不可移动。std::vector
是一个移动感知容器,在其中使用A
将会复制。 - David Rodríguez - dribeas