在派生自 move-only 类型的 class 中定义析构函数在使用 emplace_back 或 push_back of std::vector 创建时会产生编译时错误
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
从以下代码中删除注释会产生编译时错误。似乎在派生 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;
}
错误是:
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
^
我正在使用像 A 这样的基 class 来管理句柄,并且想在派生 class 中定义析构函数,主要用于调试目的。现在我在向量中使用智能指针来避免这个问题。
我想知道是什么原因造成的,以及如何通过更改代码或使用更合适的容器来解决此问题。感谢任何帮助。
编辑:
我正在编译 g++ -std=c++11
g++ 版本 g++ (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
验证您对 CopyConstructible 和 MoveConstructible 的期望 static_assert
s:
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>{});
声明~B()
时,编译器隐式删除B(B&&)
。您可以使用显式声明覆盖该行为:
B(B&&) = default;
向 std::vector
添加任何内容可能会导致整个向量的重新分配。为了成功,class 需要提供:
- 拷贝构造函数
- noexcept 移动构造函数
当 ~B
存在时,您的 class B
两者都不提供。使用 using
子句,它知道如何移动 B(A&&)
但这不是移动构造函数。
从以下代码中删除注释会产生编译时错误。似乎在派生 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;
}
错误是:
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
^
我正在使用像 A 这样的基 class 来管理句柄,并且想在派生 class 中定义析构函数,主要用于调试目的。现在我在向量中使用智能指针来避免这个问题。
我想知道是什么原因造成的,以及如何通过更改代码或使用更合适的容器来解决此问题。感谢任何帮助。
编辑:
我正在编译 g++ -std=c++11
g++ 版本 g++ (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
验证您对 CopyConstructible 和 MoveConstructible 的期望 static_assert
s:
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>{});
声明~B()
时,编译器隐式删除B(B&&)
。您可以使用显式声明覆盖该行为:
B(B&&) = default;
向 std::vector
添加任何内容可能会导致整个向量的重新分配。为了成功,class 需要提供:
- 拷贝构造函数
- noexcept 移动构造函数
当 ~B
存在时,您的 class B
两者都不提供。使用 using
子句,它知道如何移动 B(A&&)
但这不是移动构造函数。