C ++返回值和移动规则异常

问题描述 投票:0回答:1

当我们从C ++函数返回值时,会发生复制初始化。例如:

std::string hello() {
    std::string x = "Hello world";
    return x; // copy-init
}

假设禁用RVO。

根据复制初始规则,如果x是非POD类类型,则应调用复制构造函数。但是对于C ++ 11以后的版本,我看到调用了move-constrtuctor。我找不到或不了解有关此https://en.cppreference.com/w/cpp/language/copy_initialization的规则。所以我的第一个问题是-

  1. C ++标准对从函数返回值时copy-init发生的移动有何评论?

  2. 作为上述问题的扩展,我也想知道在什么情况下不会发生移动。我想出了以下情况,其中调用了copy-constructor而不是move:

std::string hello2(std::string& param) {
    return param;
}

最后,在某些库代码中,我看到返回时显式使用了std::move(即使应该发生RVO或移动)。例如:

std::string hello3() {
    std::string x = "Hello world";
    return std::move(x);
}
  1. 返回时显式使用std::move的优点和缺点是什么?
c++11 initialization move copy-constructor rvo
1个回答
0
投票

您对以下事实感到困惑,即通过move构造函数进行的初始化是“复制初始化”的一种特殊情况,并不是一个单独的概念。检查cppreference页面上的注释。

[如果other是右值表达式,将通过重载分辨率选择move构造函数,并在复制初始化期间调用它。没有诸如移动初始化之类的术语。

要从函数返回值,请检查the description of returning on cppreference。它在一个名为“从局部变量和参数自动移动”的框中表示,其中expression指的是您返回的内容(警告:引号已缩短!有关其他情况的完整详细信息,请阅读原始信息:)

如果表达式

是一个(可能用括号括起来的)id表达式,该表达式将类型为[...]的变量命名为非易失性对象类型[...],并且将该变量声明为[...]在函数的主体中,然后执行重载决议以选择用于初始化返回值的构造函数,执行两次:首先,就好像表达式是一个右值表达式(因此,它可以选择[...]移动构造函数),如果第一个重载解析失败,则照常执行重载解析,将表达式视为左值(以便它可以选择复制构造函数)。

因此,在返回局部变量的特殊情况下,即使常规语法规则将其设为l值,也可以将该变量视为r值。该规则的精神是,在返回之后,您无法确定在对返回值进行复制初始化期间是否已破坏了局部变量的值,因此移动它不会造成任何损害。

© www.soinside.com 2019 - 2024. All rights reserved.