C++11 C++;返回值和移动规则异常 当我们从C++函数返回一个值时,复制初始化发生。例如: std::string hello(){ std::string x=“Hello world”; 返回x;//复制初始化 }
假设RVO已禁用 根据copyinit规则,如果C++11 C++;返回值和移动规则异常 当我们从C++函数返回一个值时,复制初始化发生。例如: std::string hello(){ std::string x=“Hello world”; 返回x;//复制初始化 },c++11,initialization,move,copy-constructor,rvo,C++11,Initialization,Move,Copy Constructor,Rvo,假设RVO已禁用 根据copyinit规则,如果x是非POD类类型,则应调用复制构造函数。然而,对于C++11以后的版本,我看到调用了move构造函数。我无法找到或理解关于这方面的规则。所以我的第一个问题是—— 当函数从函数返回时,C++标准对复制事件发生的原因是什么? 作为对上述问题的延伸,我还想知道在哪些情况下不采取行动。我提出了以下情况,即调用复制构造函数而不是移动: std::string hello2(std::string¶m){ 返回参数; } 最后,在一些库代码中,我看
x
是非POD类类型,则应调用复制构造函数。然而,对于C++11以后的版本,我看到调用了move构造函数。我无法找到或理解关于这方面的规则。所以我的第一个问题是——
当函数从函数返回时,C++标准对复制事件发生的原因是什么?
std::string hello2(std::string¶m){
返回参数;
}
最后,在一些库代码中,我看到返回时显式使用了std::move
(即使发生了RVO或move)。例如:
std::string hello3(){
std::string x=“Hello world”;
返回std::move(x);
}
std::move
的优点和缺点是什么通过move构造函数初始化是“复制初始化”的一个特例,并且不是单独的概念,这一事实让您感到困惑。检查cppreference页面上的注释 如果另一个是右值表达式,则将通过重载解析选择移动构造函数,并在复制初始化期间调用该构造函数。没有移动初始化这样的术语 要从函数返回值,请选中。它在一个名为“从局部变量和参数自动移动”的框中显示,其中表达式指的是您返回的内容(警告:该引号缩短了!有关其他情况的详细信息,请阅读原文): 如果表达式是一个id表达式(可能用括号括起来),该表达式将类型为[…]的变量命名为非易失性对象类型[…],并且该变量在正文中声明为[…],或作为[…]函数的参数,然后,选择用于初始化返回值的构造函数的重载解析将执行两次:第一次好像表达式是右值表达式(因此它可能会选择移动构造函数),如果第一次重载解析失败[…],则重载解析将照常执行,将表达式视为左值(因此它可以选择复制构造函数) 因此,在返回局部变量的特殊情况下,可以将该变量视为r值,即使正常的语法规则会使其成为l值。该规则的精神在于,在返回后,您无法发现局部变量的值在返回值的复制初始化期间是否已被破坏,因此移动它不会造成任何损害 关于你的第二个问题:,因为不管怎样搬家都会发生
引用上面链接的C++核心指南:
切勿写入返回移动(局部变量)代码>,因为语言已经知道该变量是移动候选变量。在这段代码中写入move
不会有帮助,实际上可能是有害的,因为在某些编译器上,它会通过为局部变量创建额外的引用别名来干扰RVO(返回值优化)
因此,您引用的库代码是次优的
此外,不能从非本地的任何对象隐式移动到函数(即本地变量和值参数),因为隐式移动可能从函数返回后仍然可见的对象移动。在引用cppreference时,重点是“非易失性对象类型”。当您返回std::string¶m
时,这是一个引用类型的变量。查找“NRVO”以了解这种情况这是否回答了您的问题:这里缺少的关键点是C++11中return语句的语义