代码之家  ›  专栏  ›  技术社区  ›  itarato Randy Sugianto 'Yuku'

当“移动的”对象在联合中具有“非平凡”成员时,为什么强制复制构造函数?

  •  0
  • itarato Randy Sugianto 'Yuku'  · 技术社区  · 8 年前

    我注意到了 move 可以应用于 拥有一个与“非平凡”(不确切知道,但如基本类型很好)成员的联合。例如,编译以下代码(C++14,Clang):

    #include <vector>
    #include <string>
    
    class Foo {
    public:
      union {
        int i;
        bool b;
      };
    
      Foo() {};
      ~Foo() {};
    
      // Move constructor to default.
      Foo(Foo &&) = default;
    
      // Copy constructor deleted.
      Foo(const Foo &) = delete;
    };
    
    int main() {
      std::vector<Foo> v;
      v.push_back(Foo());
    }
    

    请注意,复制构造函数已被删除。自从 std::vector push_back 可以接受右值引用,在这种情况下,它将使用右值引用,而不接受右值引用 copy 将发生。但是,一旦将“非平凡”类型添加到联合中,就会强制复制构造函数,因此它将不会编译:

    #include <vector>
    #include <string>
    
    class Foo {
    public:
      union {
        int i;
        bool b;
        std::string s; // <-- Added element causing compile error.
      };
    
      Foo() {};
      ~Foo() {};
    
      // Move constructor to default.
      Foo(Foo &&) = default;
    
      // Copy constructor deleted.
      Foo(const Foo &) = delete;
    };
    
    int main() {
      std::vector<Foo> v;
      v.push_back(Foo());
    }
    

    编译器错误消息的相关部分:

    In file included from experiment/miniso.cpp:1:
    In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/vector:61:
    In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/allocator.h:46:
    In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/x86_64-linux-gnu/c++/7.2.0/bits/c++allocator.h:33:
    /usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/ext/new_allocator.h:136:23: error: call to deleted constructor of 'Foo'
            { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
                                 ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/alloc_traits.h:475:8: note: in instantiation of function template
          specialization '__gnu_cxx::new_allocator<Foo>::construct<Foo, Foo>' requested here
            { __a.construct(__p, std::forward<_Args>(__args)...); }
                  ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/vector.tcc:100:21: note: in instantiation of function template
          specialization 'std::allocator_traits<std::allocator<Foo> >::construct<Foo, Foo>' requested here
                _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
                               ^
    /usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/stl_vector.h:954:9: note: in instantiation of function template
          specialization 'std::vector<Foo, std::allocator<Foo> >::emplace_back<Foo>' requested here
          { emplace_back(std::move(__x)); }
            ^
    experiment/miniso.cpp:24:5: note: in instantiation of member function 'std::vector<Foo, std::allocator<Foo> >::push_back' requested here
      v.push_back(Foo());
        ^
    experiment/miniso.cpp:19:3: note: 'Foo' has been explicitly marked deleted here
      Foo(const Foo &) = delete;
      ^
    

    目标编译器是C++14。

    1 回复  |  直到 8 年前
        1
  •  3
  •   Nicol Bolas    8 年前

    它试图调用你的复制构造函数,因为你的移动构造函数是 删除 . 哦,当然,我知道你写了 = default . 但是,由于联合包含一个具有非平凡移动/复制构造函数的类型,因此如果联合的复制/移动构造函数不是用户提供的,则它将被隐式删除。

    =默认值

    换句话说,编译器不能给出 union 复制/移动构造函数,如果其任何成员需要复制/移动除 memcpy (又名:不可复制)。因此,包含联合的类型也不能有编译器生成的复制/移动代码。在这些情况下,必须由您决定如何复制/移动对象。

    这样的复制/移动构造函数需要知道它是哪种类型。