RVO是否需要在C ++ 11中启动移动构造函数/分配?

时间:2019-06-26 17:32:41

标签: c++11 move-semantics copy-elision rvo nrvo

例如:

在接受的答案https://stackoverflow.com/a/14623480/1423254中,

  

复制省略和RVO仍可在不移动的情况下用于类   构造函数?

     

是的,RVO仍然起作用。实际上,预期编译器会选择:   RVO(如果可能)

在接受的答案https://stackoverflow.com/a/38043447/1423254中,

  

在无保证的复制省略规则下,这将创建一个临时的,   然后从该临时变量移至函数的返回值。那   可以取消移动操作,但是T必须仍然可以进行移动   构造函数,即使它从未使用过。

重点是,我认为RVO和“左值移动”(或如何称呼它们)是两个完全独立的操作,但是我的同事告诉我,要插入RVO,返回的类需要一个move构造函数。因此,我检查了互联网和SO,显然无法迅速找到该信息...

2 个答案:

答案 0 :(得分:1)

简短的回答:不。

RVO在C ++ 11之前也存在,当时没有诸如“移动构造函数”之类的东西。在这种情况下,复制构造函数是唯一的要求。

您引述的“在无保证的复制省略规则下……” 段落是指C ++ 17之前的世界,其中“强制复制省略”还不是该语言的一部分

从C ++ 17开始,以下代码进行编译(保证零拷贝/移动):

struct foo
{
    foo() = default;
    foo(const foo&) = delete;
    foo(foo&&) = delete;
};

foo get_foo() { return foo{}; }

int main()
{
    foo f{get_foo()};
}

答案 1 :(得分:1)

否,如果可以访问副本构造函数。

在C ++ 17之前并保证复制删除, 必须有移动构造函数或复制构造函数才能使代码合法。 Elision只是一种优化,不会影响代码是否会编译。

也就是说,有两个步骤:

  • 评估语句return <expr>;是否合法,在C ++ 17之前,该语句要求(禁止转换)存在复制构造函数或在存在临时构造函数的情况下移动构造函数,可访问
  • 如果可能,请应用“返回值优化”并将调用取消到所述构造函数。

考虑到这一点,让我们回顾一下引号:

  
    

在没有移动构造函数的情况下,复制省略和RVO是否仍适用于类?

  
     

是的,RVO仍然起作用。实际上,编译器应该选择:RVO(如果可能)

应在合法代码的上下文中理解“是”。如果代码无法编译,那么问题就没有意义了。

  

在无保证的复制省略规则下,这将创建一个临时变量,然后从该临时变量移至函数的返回值。可以省略该移动操作,但是T仍然必须具有可访问的move构造函数,即使它从未使用过。

这是捷径;尝试考虑可能没有移动构造函数的语句来构造句子,因此,复制构造函数的后备内容只会使解释变得混乱,OP并未表示正在考虑这种情况。