简体   繁体   English

在从仅移动类型派生的 class 中定义析构函数会在使用 std::vector 的 emplace_back 或 push_back 创建时产生编译时错误

[英]defining destructor in a class derived from move-only type gives compile-time error when created with emplace_back or push_back of std::vector

Removing the comment from following code gives a compile time error.从以下代码中删除注释会产生编译时错误。 It seems that defining the destructor in derived class is causing the copy constructor to be called in emplace_back似乎在派生的 class 中定义析构函数会导致在 emplace_back 中调用复制构造函数

#include <vector>

struct A
{
    A() = default;
    A( A& ) = delete;
    A& operator=( A& ) = delete;
    A( A&& ) = default;
    A& operator=( A&& ) = default;
    ~A(){};
};

struct B : public A
{
    using A::A;
    //~B() = default; //ERROR
};

int main()
{
    std::vector< B > list;
    for( int ii = 0; ii < 3; ii++ ) { list.emplace_back(); }
    return 0;
}

The error is:错误是:

In file included from /usr/include/c++/5/vector:62:0,
                 from a.cpp:1:
/usr/include/c++/5/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = B; _Args = {B}]’:
/usr/include/c++/5/bits/stl_uninitialized.h:75:18:   required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<B*>; _ForwardIterator = B*; bool _TrivialValueTypes = false]’
/usr/include/c++/5/bits/stl_uninitialized.h:126:15:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<B*>; _ForwardIterator = B*]’
/usr/include/c++/5/bits/stl_uninitialized.h:281:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<B*>; _ForwardIterator = B*; _Tp = B]’
/usr/include/c++/5/bits/stl_uninitialized.h:303:2:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = B*; _ForwardIterator = B*; _Allocator = std::allocator<B>]’
/usr/include/c++/5/bits/vector.tcc:422:8:   required from ‘void std::vector<_Tp, _Alloc>::_M_emplace_back_aux(_Args&& ...) [with _Args = {}; _Tp = B; _Alloc = std::allocator<B>]’
/usr/include/c++/5/bits/vector.tcc:101:23:   required from ‘void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = B; _Alloc = std::allocator<B>]’
a.cpp:24:57:   required from here
/usr/include/c++/5/bits/stl_construct.h:75:7: error: invalid initialization of non-const reference of type ‘B&’ from an rvalue of type ‘B’
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^
a.cpp:15:8: note:   initializing argument 1 of ‘B::B(B&)’
 struct B : public A
        ^

I am using the base class like A for managing HANDLEs, and want to define destructor in derived class mostly for debugging purposes.我使用像 A 一样的基本 class 来管理 HANDLE,并且想在派生的 class 中定义析构函数,主要用于调试目的。 For now I am using smart pointers in vectors to avoid this issue.现在我在向量中使用智能指针来避免这个问题。

I am wondering what is causing this and how to fix this by either changes in code or using more suitable container.我想知道是什么原因造成的,以及如何通过更改代码或使用更合适的容器来解决这个问题。 Any help is appreciated.任何帮助表示赞赏。

Edit: I am compiling with g++ -std=c++11 g++ version g++ (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609 Edit: I am compiling with g++ -std=c++11 g++ version g++ (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609

Verify your expectations of CopyConstructible and MoveConstructible with static_assert s:使用static_assert验证您对CopyConstructibleMoveConstructible的期望:

static_assert(!std::is_copy_constructible<A>{});
static_assert( std::is_move_constructible<A>{});

static_assert(!std::is_copy_constructible<B>{});
static_assert(!std::is_move_constructible<B>{});

When ~B() is declared, the compiler implicitly deletes B(B&&) .声明~B()时,编译器会隐式删除B(B&&) You can override that behavior with an explicit declaration:您可以使用显式声明覆盖该行为:

B(B&&) = default;

Adding anything to the std::vector may potentially cause reallocation of the whole vector.std::vector添加任何内容可能会导致整个向量的重新分配。 For this to succeed the class needs to provide either:为了成功,class 需要提供:

  • copy constructor复制构造函数
  • noexcept move constructor noexcept 移动构造函数

When ~B is present, your class B provides neither.~B存在时,您的 class B两者都不提供。 With the using clause it knows how to move B(A&&) but that's not a move constructor.使用using子句,它知道如何移动B(A&&) ,但这不是移动构造函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM