复制/移动精确对比显式删除的复制/移动构造函数 [英] Copy/move elision versus explicitly deleted copy/move constructors

查看:236
本文介绍了复制/移动精确对比显式删除的复制/移动构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道何时复制/移动elision应用(或允许应用)显式地删除 d复制/移动构造函数和非 - delete d复制/移动构造函数。具体如下:


  1. 可以显式地删除或移动ctor获取?是尝试通过跳过 delete d copy ctor和/或从另一个相同类型的对象或临时对象中构建一个对象,删除 d move ctor?



    这里是在VC12发生了什么(我不知道是否有一个选项禁用复制/ elision):

      #include< iostream> 

    struct Foo {
    Foo(){std :: cout< default ctor\ n; }
    Foo(Foo const&)= delete;
    Foo(Foo&&)= delete;
    };

    int main(){
    // ----输出------
    Foo {Foo()}; //default ctor
    Foo f; //default ctor
    Foo {std :: move(f)}; //错误C2280:'Foo :: Foo(Foo&&);尝试引用一个删除的函数
    Foo {f}; //错误C2280:'Foo :: Foo(const Foo&)':尝试引用一个已删除的函数
    }

    即使IntelliSense抱怨 Foo {Foo()}; 错误:functionFoo :: Foo &&&&&&&&&&&)... $ b

  2. 为什么 Foo {Foo()}; 工作,但不是 Foo {std :: move(f)} ;


  3. 为什么 Foo {Foo()}; 工作,但不是 Foo {f}; ?这种选择性看起来是任意的。这种对于const引用的右值引用的任意偏好(或反之亦然)似乎不适用于非ctor方法;其中在调用中,如果 delete d重载,否则将具有比非删除 c> d重载, delete d一个块会阻塞非 - delete d,导致编译器错误:

      struct Bar {
    void g(int const&){}
    void g(int&删除;
    };

    // ...
    Bar b;
    b.g(2); //错误C2280:'void Bar :: g(int&&)'尝试引用一个已删除的函数
    // ^将编译过的函数`g(int& 。

    根据该逻辑, delete d Foo(Foo&&)不应阻止对 Foo(Foo const&)不是临时的;在这种情况下, Foo(Foo&&)的重载解析优先级低于 Foo(Foo const&)


  4. 我尝试过在g ++ 4.8中使用相同的 Foo 示例, code> -fno-elide-constructors ),并再次启用它。两个g ++试验给出:



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



    错误: Foo {f};



    哪个编译器是正确的?



解决方案

非常老的知名bug。从C ++标准


[注意:无论是否发生复制错误,都必须执行
这两个阶段的重载分辨率。如果不执行elision,它确定要调用的
构造函数,并且即使调用被省略,所选的
构造函数也必须可访问。 -end note]



I want to know when copy/move elision applies (or is allowed to apply) to explicitly deleted copy/move constructors and to non-deleted copy/move constructors. Here are the specifics:

  1. Can an explicitly deleted copy ctor or move ctor get elided? Is an attempt to construct an object from another same-type object or temporary object ever allowed to succeed by skipping over the deleted copy ctor and/or deleted move ctor?

    Here’s what happens in VC12 (with which I’m not sure if there is an option to disable copy/move elision):

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

    Even though IntelliSense complains about Foo{ Foo() };: Error: function "Foo::Foo(Foo &&)" ... cannot be referenced – it is a deleted function, the compiler doesn't complain there, so that line still compiles.

  2. Why does Foo{ Foo() }; work, but not Foo{ std::move(f) };? If one call elides the move ctor, then shouldn’t the other?

  3. Why does Foo{ Foo() }; work, but not Foo{ f };? This selectivity looks arbitrary. This kind of arbitrary preference of rvalue reference over const reference (or vice versa) doesn’t seem to apply to non-ctor methods; where in a call, if a deleted overload that would otherwise have a higher overload resolution priority than a non-deleted overload, the deleted one blocks the non-deleted one, resulting in a compiler error:

    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.
    

    According to that logic, a deleted Foo(Foo&&) shouldn’t block a call to Foo(Foo const&) when the argument is not a temporary; Foo(Foo&&) would have a lower overload resolution priority than Foo(Foo const&) in that case.

  4. I tried the same Foo example in g++ 4.8 with copy elision disabled (via the flag -fno-elide-constructors) and again with it enabled. Both g++ trials gave:

    error: use of deleted function 'Foo::Foo(Foo&&)' for Foo{ Foo() }; and

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

    Which compiler is correct?

解决方案

Ms VC ++ has a very old well-known bug. From the C++ Standard

[ 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 ]

这篇关于复制/移动精确对比显式删除的复制/移动构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆