按值返回std::vector

18

常言道,在 C++11 中,通过值返回 std::vector 是合理的。

在 C++03 中,由于 RVO 可以优化掉拷贝操作,这通常是正确的,但是这个“应该”让大多数开发人员感到不安。

  • 在 C++11 中,返回的局部变量 std::vector 是否总是会被移动?
  • 如果该向量是局部变量的成员而不是局部变量本身呢?
  • 显然返回全局变量将不会被移动。还有哪些情况它不会被移动?

请参考这个问题 - Xeo
2个回答

15

首先,每当可以省略复制时,现在仍然可以省略复制,并且在相同情况下也可以省略移动操作。在此后的文章中,我假设由于某种原因未发生省略(假设编译器写作人员懒惰得很糟糕)。

在C++11中,返回的std::vector局部变量是否总是会被移动?

只要符合复制省略的条件,或者该变量显式使用了std::move,就会被移动。

如果这个向量是一个局部变量的成员而不是局部变量本身呢?

除非显式使用std::move,否则不会被移动。

显然,返回全局变量不会被移动。还有什么其他情况不会被移动吗?

只要不符合复制省略的条件并且该变量没有显式使用std::move,就不会被移动。

以上都不是不返回值的有效理由。返回值是可以的,因为即使值没有自动移动,也可以强制使用std::move来移动它。


如果可以进行RVO优化,我认为它不会被移动。 - juanchopanza
@juanchopanza 嗯,是的,这些都不会阻止优化。 - R. Martinho Fernandes
好的,你的第一个观点似乎意味着每当复制省略的条件得到满足时,它都将被移动。 - juanchopanza
@juanchopanza 你是对的。现在我把它都弄清楚了。我想是这样。 - R. Martinho Fernandes
1
也许我误解了您所说的“复制省略标准”,但是:http://ideone.com/QK34O - Benjamin Lindley
64位Linux ABI要求调用者为返回值分配空间,如果它不适合于2个寄存器。这意味着编译器别无选择,只能实现[N]RVO。(注:指命名返回值优化技术) 参见http://www.agner.org/optimize/calling_conventions.pdf。 - Maxim Egorushkin

8
在C++11中,返回的 std::vector 本地变量是否总是会被移动?
对于本地变量,即使是按值传递的参数,编译器也必须首先尝试将其移动(即使满足标准,但如果既不能移动也不能复制,则仍需尝试)。如果移动失败,则再尝试复制:
§12.8 [class.copy] p32
当符合复制操作省略标准的条件时(或者除了源对象是函数参数这个事实,其他条件都符合),并且要复制的对象由左值指定时,优先执行重载决议以选择用于复制的构造函数,就好像对象是由右值指定的一样。如果重载决议失败,或者所选构造函数的第一个参数的类型不是对象类型的右值引用(可能带有cv限定符),则再次进行重载决议,将对象视为左值。(注意:无论是否发生复制省略,都必须执行此两阶段重载决议。它确定要在未执行省略时调用的构造函数,并且选定的构造函数必须可访问,即使调用被省略。 - end note)
那么,如果该向量是本地变量的成员而不是本地变量本身呢?
子对象不会尝试移动,因为这不符合复制省略的标准。 (在我看来很荒谬,但这就是当前的情况。我认为两者不应该关联,因为子对象可以完全自由地移动。)
显然,返回全局变量将不会被移动。还有哪些情况不会被移动?
引用显然不会被移动。除此之外,我想不出其他情况。

一个本地引用的参考怎么样?如果在本地引用上调用std::move会怎么样? - deft_code
@deft_code:一个引用本身不会自动移动,似乎我的最后一句话在这方面不够清楚。std::move的引用将移动所引用的对象。 - Xeo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接