C++14 中的 RVO 和删除的移动构造函数

RVO and deleted move constructor in C++14

最近几天我一直在学习 (N)RVO。正如我在复制省略文章中阅读 cppreference 时,对于 C++14:

... the compilers are permitted, but not required to omit the copy- and move- (since C++11)construction of class objects even if the copy/move (since C++11) constructor and the destructor have observable side-effects. This is an optimization: even when it takes place and the copy-/move-constructor is not called, it still must be present and accessible (as if no optimization happened at all), otherwise the program is ill-formed.

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

#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.

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

引自cppreference

Deleted functions

If, instead of a function body, the special syntax = delete ; is used, the function is defined as deleted.

...

If the function is overloaded, overload resolution takes place first, and the program is only ill-formed if the deleted function was selected.

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

如果删除显式 delete,则会选择复制构造函数并编译您的程序。