c++ - 复制/move 省略与显式删除的复制/move 构造函数

标签 c++ constructor move-semantics delete-operator copy-elision

我想知道复制/move 省略何时适用(或允许应用)显式删除复制/move 构造函数和非删除复制/move 构造函数。具体内容如下:

  1. 显式删除的复制构造函数或 move 构造函数是否可以被删除?尝试从另一个相同类型的对象或临时对象构造对象是否可以通过跳过删除复制函数和/或删除 move 函数来成功?

    这是 VC12 中发生的情况(我不确定是否有禁用复制/move 省略的选项):

    #include <iostream>
    
    struct Foo {
        Foo() { std::cout << "default ctor\n"; }
        Foo(Foo const&) = delete;
        Foo(Foo&&) = delete;
    };
    
    int main() {
                             // ----Output------
        Foo{ Foo() };        // "default ctor"
        Foo f;               // "default ctor"
        Foo{ std::move(f) }; // error C2280: 'Foo::Foo(Foo &&)' : attempting to reference a deleted function
        Foo{ f };            // error C2280: 'Foo::Foo(const Foo &)' : attempting to reference a deleted function
    }
    

    尽管 IntelliSense 提示 Foo{ Foo() };: Error: function “Foo::Foo(Foo &&)” ... 无法引用 – 它已被删除function,编译器不会在那里提示,因此该行仍然可以编译。

  2. 为什么 Foo{ Foo() }; 可以工作,但 Foo{ std::move(f) }; 不行?如果一个调用忽略了 move ctor,那么另一个调用也不应该这样做吗?

  3. 为什么 Foo{ Foo() }; 可以工作,但 Foo{ f }; 不行?这种选择性看起来是任意的。这种右值引用相对于 const 引用的任意偏好(反之亦然)似乎不适用于非构造方法;在调用中,如果 deleted 重载的重载解析优先级高于非 deleted 重载,则 delete d 一个会阻塞非deleted 一个,从而导致编译器错误:

    struct Bar {
        void g(int const&) {}
        void g(int&&) = delete;
    };
    
    //…
    Bar b;
    b.g(2); //error C2280: 'void Bar::g(int &&)' : attempting to reference a deleted function
    // ^ Would have compiled had function `g(int&&)` been commented out.
    

    根据该逻辑,当 deleted Foo(Foo&&)争论不是暂时的;在这种情况下,Foo(Foo&&) 的重载解析优先级将低于 Foo(Foo const&)

  4. 我在 g++ 4.8 中尝试了相同的 Foo 示例,禁用复制省略(通过标志 -fno-elide-constructors),然后再次启用它。两项 g++ 试验均给出:

    错误:对 Foo{ Foo() }; 使用已删除的函数 'Foo::Foo(Foo&&)'

    错误:对 Foo{ f }; 使用已删除的函数 'Foo::Foo(const Foo&)'

    哪个编译器是正确的?

最佳答案

VC++女士有一个非常古老的众所周知的错误。来自 C++ 标准

[ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. —end note ]

关于c++ - 复制/move 省略与显式删除的复制/move 构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20589622/

相关文章:

c++ - Ant 在长方体中找到最短路径 : length, 给出了长方体的宽度和高度。输出应以浮点形式显示最短距离

c++ - 如何复制一个非平凡的 C++ union ?

c++ - 正确取消引用 2D 动态数组?

c++ CDialog ID 更改

java - 构造函数没有任何返回类型,但是对象是如何创建的呢?

c++ - 在递归数据结构中 move unique_ptr<T> 数组

c++ - 重写构造函数 C++

c# - 基本构造函数未被调用

c++ - 使用 std::move 实现 "take"方法

c++ - 何时对引用或唯一指针使用 move 语义?