[英]Class with explicit destructor and std::unique_ptr<> member can't be used in std::vector<>?
This code 这段代码
#include <memory>
#include <vector>
class Foo
{
public:
~Foo()
{
}
std::unique_ptr<int> bar;
};
int main()
{
std::vector<Foo> foos;
foos.emplace_back();
}
yields the following error message in g++: 在g ++中产生以下错误消息:
In file included from /usr/include/c++/4.8/memory:64:0,
from main.cpp:1:
/usr/include/c++/4.8/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = Foo; _Args = {Foo}]’:
/usr/include/c++/4.8/bits/stl_uninitialized.h:75:53: required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<Foo*>; _ForwardIterator = Foo*; bool _TrivialValueTypes = false]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:117:41: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<Foo*>; _ForwardIterator = Foo*]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:258:63: required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<Foo*>; _ForwardIterator = Foo*; _Tp = Foo]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:281:69: required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = Foo*; _ForwardIterator = Foo*; _Allocator = std::allocator<Foo>]’
/usr/include/c++/4.8/bits/vector.tcc:415:43: required from ‘void std::vector<_Tp, _Alloc>::_M_emplace_back_aux(_Args&& ...) [with _Args = {}; _Tp = Foo; _Alloc = std::allocator<Foo>]’
/usr/include/c++/4.8/bits/vector.tcc:101:54: required from ‘void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = Foo; _Alloc = std::allocator<Foo>]’
main.cpp:17:23: required from here
/usr/include/c++/4.8/bits/stl_construct.h:75:7: error: use of deleted function ‘Foo::Foo(const Foo&)’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^
main.cpp:4:7: note: ‘Foo::Foo(const Foo&)’ is implicitly deleted because the default definition would be ill-formed:
class Foo
^
main.cpp:4:7: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’
In file included from /usr/include/c++/4.8/memory:81:0,
from main.cpp:1:
/usr/include/c++/4.8/bits/unique_ptr.h:273:7: error: declared here
unique_ptr(const unique_ptr&) = delete;
yet if I remove the ~Foo()
implementation (and declaration) it compiles just fine. 但是,如果我删除
~Foo()
实现(和声明),它编译就好了。 The same behaviour can be observed would main()
look like this: 可以观察到相同的行为,
main()
看起来像这样:
int main()
{
auto f = Foo();
}
Why is the copy constructor of Foo
being called anyway? 为什么
Foo
调用Foo
的拷贝构造函数? Shouldn't everything here happen via move semantics? 难道不应该通过移动语义来实现这里的一切吗?
Why wouldn't it (the copy constructor) be implicitly deleted if I remove the destructor? 如果我删除析构函数,为什么不隐式删除它(复制构造函数)?
The explicit destructor declaration (and definition) suppresses the implicit declaration of the move constructor and the move assignment operator. 显式析构函数声明(和定义)禁止移动构造函数和移动赋值运算符的隐式声明。 Thus the only thing that can be used is the copy constructor (which is implicitly declared no matter what) - but it's defined as deleted because
unique_ptr
s are not copyable. 因此,唯一可以使用的是复制构造函数(无论什么都隐式声明) - 但它被定义为已删除,因为
unique_ptr
是不可复制的。 Hence the error. 因此错误。
Explicitly default them - and the default constructor too since you have a user-declared constructor now: 显式默认它们 - 以及默认构造函数,因为你现在有一个用户声明的构造函数:
Foo() = default;
Foo(Foo&&) = default;
Foo& operator=(Foo&&) = default;
Why wouldn't it (the copy constructor) be implicitly deleted if I remove the destructor?
如果我删除析构函数,为什么不隐式删除它(复制构造函数)?
It's still implicitly deleted. 它仍被隐式删除。 But since now a move constructor is implicitly declared, the move constructor can used for moving, and the copy constructor simply isn't used.
但是由于现在隐式声明了一个移动构造函数,移动构造函数可以用于移动,而复制构造函数根本就没有被使用。
Relevant standard quote (§12.8 [class.copy]/p9, 20, emphasis added): 相关标准引用(§12.8[class.copy] / p9,20,重点补充):
9 If the definition of a class
X
does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if9如果类
X
的定义没有显式声明一个移动构造函数,那么当且仅当一个移动构造函数被隐式声明为默认值时
X
does not have a user-declared copy constructor,X
没有用户声明的复制构造函数,X
does not have a user-declared copy assignment operator,X
没有用户声明的复制赋值运算符,X
does not have a user-declared move assignment operator, andX
没有用户声明的移动赋值运算符,和X
does not have a user-declared destructor .X
没有用户声明的析构函数 。20 If the definition of a class
X
does not explicitly declare a move assignment operator, one will be implicitly declared as defaulted if and only if20如果类
X
的定义没有显式地声明一个移动赋值运算符,那么当且仅当一个运算符默认时,它将被隐式声明为默认值
X
does not have a user-declared copy constructor,X
没有用户声明的复制构造函数,X
does not have a user-declared move constructor,X
没有用户声明的移动构造函数,X
does not have a user-declared copy assignment operator, andX
没有用户声明的复制赋值运算符,和X
does not have a user-declared destructor .X
没有用户声明的析构函数 。
Foo
is not copyable since it has a member unique_ptr
. Foo
不可复制,因为它有一个成员unique_ptr
。 Foo
is also not movable because declaration of a user-provided destructor suppresses the implicit generation of the default move constructor / assignment. Foo
也不可移动,因为声明用户提供的析构函数会抑制默认移动构造函数/赋值的隐式生成。 If you want Foo
to be movable default the move constructor/assignment so the compiler will generate them for you: 如果你希望
Foo
是可移动的默认移动构造函数/赋值,那么编译器将为你生成它们:
class Foo
{
public:
~Foo()
{
}
Foo(Foo&&) = default;
Foo& operator=(Foo&&) = default;
std::unique_ptr<int> bar;
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.