复制省略是几乎每个编译器都支持的允许优化。
复制省略意味着在某些情况下,创建临时副本,然后将该临时副本复制到命名变量中,然后销毁临时副本,可以直接构造变量。
与返回值优化和移动语义一起,意味着返回可移动的复杂对象是高效的。对于像int
as-if 规则这样的类型也在运行中:编译器可以做任何表现得好像代码行或代码块被执行的事情,并且编译器理解当你复制/移动时会发生什么int
(即,基本上什么都没有),所以他们可以跳过那些复制/移动。
为确保 RVO 和复制省略正确发生,您需要执行以下操作:
int function() {
int retval = 8; // create the return value in one spot, this makes NRVO possible
// code goes here
return retval; // you can have more than one return statement in most compilers
}
int result = function(); // initialize the variable result by assigning the return value of the function to it.
如果您执行上述操作,大多数编译器将retval
直接在result
变量存储中构造对象,根本不会出现任何副本 iffunction
的主体可以看到result
(有些可能会这样做,即使您看不到function
mayhap 的主体)
在 C++11 中还有其他技巧。
int function() {
return {7}; // guaranteed to directly construct the return value without a copy
}
int result = function(); // even if copy elision is not done, the temporary `int` is moved into `result`.
如果你阻止复制省略:
int function() {
int foo = 7;
int bar = 3;
// code
if (foo>bar)
return foo;
else
return bar;
}
只要您返回一个局部变量,就会发生隐式移动。你也可以显式地std::move
放入返回值。
现在,对于像 . 这样简单而小的类型int
,所有这些优化都毫无意义。当您处理更大、昂贵的对象时,例如 a std::vector
of std::vector
s,其中每个对象都包含 10 MB 的数据,这些技术意味着按值返回最终与传递要仔细填充的指针一样有效。