【问题标题】:RVO and deleted move constructor in C++14C++14 中的 RVO 和删除的移动构造函数
【发布时间】:2018-02-03 19:12:23
【问题描述】:

过去几天我一直在学习 (N)RVO。正如我在复制省略文章中所读到的 C++14 中的 cppreference :

... 允许编译器,但不需要省略类对象的复制和移动(C++11 起)构造,即使复制/移动(C++11 起)构造函数和析构函数也是如此有明显的副作用。这是一个优化:即使它发生并且 copy-/move-constructor 没有被调用,它仍然必须存在并且可访问(好像没有优化发生在all),否则程序格式错误。

因此,复制 移动构造函数必须存在且可访问。但在下面的代码中:

#include <iostream>

class myClass
{
public:
    myClass() { std::cout << "Constructor" << std::endl; }
    ~myClass() { std::cout << "Destructor" << std::endl; }

    myClass(myClass const&) { std::cout << "COPY constructor" << std::endl;}
    myClass(myClass &&) = delete;
};

myClass foo()
{
    return myClass{};
}

int main()
{
    myClass m = foo();
    return 0;
}

我收到以下错误:test.cpp: In function 'myClass foo()': test.cpp:15:17: error: use of deleted function 'myClass::myClass(myClass&&)' return myClass{};。即使我不从main() 调用foo(),我也会收到此错误。 NRVO 也有同样的问题。

因此总是需要移动构造函数,不是吗? (虽然副本不是,但我检查了它)

我不明白编译器在哪里需要移动构造函数。我唯一的猜测是构造临时变量可能需要它,但这听起来令人怀疑。有人知道答案吗?

关于编译器:我在g++和VS编译器上试过,可以在线查看:http://rextester.com/HFT30137

附:我知道在 C++17 标准中,RVO 是有义务的。但是 NRVO 不是,所以我想研究一下这里发生了什么,以了解何时可以使用 NRVO。

【问题讨论】:

  • 使用 gcc 7.2 编译为 C++ 17
  • 经验法则:永远不要明确删除移动操作。而是明确定义或删除复制操作,这会抑制移动的生成。唯一显式删除移动操作会产生影响的情况是,您最终会得到一种病态的可复制但不可移动的类型。
  • @Casey,所以,唯一的情况是,当可以删除移动运算符时,是当你删除复制和移动时?或者在这种情况下删除移动操作符是不必要的?

标签: c++ c++14 move-constructor


【解决方案1】:

引用自cppreference:

删除的函数

如果,而不是函数体,特殊语法 = delete ;被使用,函数定义为删除。

...

如果函数被重载,重载决议首先发生,只有当被删除的函数被选中时,程序才是非良构的。

如果你明确定义要删除的移动构造函数,那就不一样了。这里因为这个删除的move构造函数的存在,虽然copy构造函数可以匹配,但是move构造函数更好,所以重载解析时选择move构造函数。

如果你删除显式的delete,那么复制构造函数将被选中并且你的程序将被编译。

【讨论】:

  • 很好的答案,但我建议进行编辑以说明即使 Copy 构造函数存在并且很好,但 move 构造函数更适合并且被选中而不是复制构造函数。
  • 谢谢。我曾经写过明确的delete,目的是禁止使用默认构造函数。据我所知,如果我定义了一个复制构造函数,则不会创建默认的移动构造函数。是吗?
  • @user4581301 有用户声明的copy-constructor,所以没有隐式声明move构造函数,所以会调用copy-constructor。
  • @user4581301 答案已更新,解释简单。实际上这里的返回值是一个右值,结果很容易预测。但是即使在 OP 的函数中返回了一个左值,它仍然是要选择的移动构造函数。引用所有这些材料来回答答案可能太冗长了。
  • @AnyaMitrushchienkova 是的,编译器不会生成它。
猜你喜欢
  • 1970-01-01
  • 2014-07-15
  • 1970-01-01
  • 1970-01-01
  • 2018-03-26
  • 1970-01-01
  • 2017-09-10
  • 1970-01-01
  • 2018-08-30
相关资源
最近更新 更多