2

我想知道复制/移动省略何时适用(或允许应用)显式delete复制/移动构造函数和非delete复制/移动构造函数。以下是具体情况:

  1. 可以省略明确的deleted 复制 ctor 或移动 ctor 吗?delete是否允许通过跳过d 复制 ctor 和/或deleted 移动 ctor从另一个相同类型的对象或临时对象构造对象的尝试成功?

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

    #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 &&)” ... cannot be referenced – it is a deleted function,编译器也不会抱怨,因此该行仍然可以编译。

  2. 为什么Foo{ Foo() };有效,但无效Foo{ std::move(f) };?如果一个电话忽略了移动 ctor,那么另一个电话不应该吗?

  3. 为什么Foo{ Foo() };有效,但无效Foo{ f };?这种选择性看起来很随意。这种右值引用优于 const 引用(反之亦然)的任意偏好似乎不适用于非 ctor 方法;在调用中,如果deleted 重载具有比非deleted 重载更高的重载决议优先级,则deleted 会阻塞非 d 重载,delete从而导致编译器错误:

    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.
    

    根据该逻辑,当参数不是临时参数时, a deletedFoo(Foo&&)不应阻止调用;将具有比在这种情况下更低的重载解决优先级。Foo(Foo const&)Foo(Foo&&)Foo(Foo const&)

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

    error: use of deleted function 'Foo::Foo(Foo&&)'对于Foo{ Foo() };

    error: use of deleted function 'Foo::Foo(const Foo&)'为了Foo{ f };

    哪个编译器是正确的?

4

1 回答 1

4

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

[注意:无论是否会发生复制省略,都必须执行此两阶段重载解析。它确定如果不执行省略则要调用的构造函数,并且即使调用被省略,所选构造函数也必须是可访问的。——尾注]

于 2013-12-15T00:00:44.330 回答