代码在没有用户定义析构函数的情况下(在GCC 4.7.2上)编译得很好,即使提供了空的用户定义析构函数也会产生错误:
#include <memory>
class Test
{
std::unique_ptr<int> val;
};
template <typename Type>
class B
{
public:
//destructor:
// if I comment this out, the code compiles just fine:
~B() { }
private:
Test a;
};
int main()
{
auto s = B<int>();
}
析构函数未被注释掉时所产生的错误的重点是:
- Test的复制构造函数不存在,并且没有隐式创建,因为它将是错误的
- 有人试图使用已删除的unique_ptr复制构造函数。
完整的错误输出,对于感兴趣的人来说,在这篇文章的底部。
我知道unique_ptr
不能被复制构造(除非参数是右值),因此编译器不可能为类Test
生成有效的隐式复制构造函数。
我不明白的是为什么定义一个空的析构函数突然需要这些复制工具。显然,当使用unique_ptr
s之类的东西时,这是不可能提供的。
析构函数未被注释掉时的完整错误输出:
In file included from /usr/include/c++/4.7/list:64:0,
from ../../Dropbox/Programming/C++/test/main.cpp:2:
/usr/include/c++/4.7/bits/stl_list.h: In instantiation of 'std::_List_node<_Tp>::_List_node(_Args&& ...) [with _Args = {const Test&}; _Tp = Test]':
/usr/include/c++/4.7/ext/new_allocator.h:110:4: required from 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::_List_node<Test>; _Args = {const Test&}; _Tp = std::_List_node<Test>]'
/usr/include/c++/4.7/bits/stl_list.h:503:8: required from 'std::list<_Tp, _Alloc>::_Node* std::list<_Tp, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {const Test&}; _Tp = Test; _Alloc = std::allocator<Test>; std::list<_Tp, _Alloc>::_Node = std::_List_node<Test>]'
/usr/include/c++/4.7/bits/stl_list.h:1533:63: required from 'void std::list<_Tp, _Alloc>::_M_insert(std::list<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {const Test&}; _Tp = Test; _Alloc = std::allocator<Test>; std::list<_Tp, _Alloc>::iterator = std::_List_iterator<Test>]'
/usr/include/c++/4.7/bits/stl_list.h:997:9: required from 'void std::list<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = Test; _Alloc = std::allocator<Test>; std::list<_Tp, _Alloc>::value_type = Test]'
/usr/include/c++/4.7/bits/stl_list.h:1466:6: required from 'void std::list<_Tp, _Alloc>::_M_initialize_dispatch(_InputIterator, _InputIterator, std::__false_type) [with _InputIterator = std::_List_const_iterator<Test>; _Tp = Test; _Alloc = std::allocator<Test>]'
/usr/include/c++/4.7/bits/stl_list.h:582:9: required from 'std::list<_Tp, _Alloc>::list(const std::list<_Tp, _Alloc>&) [with _Tp = Test; _Alloc = std::allocator<Test>; std::list<_Tp, _Alloc> = std::list<Test>]'
../../Dropbox/Programming/C++/test/main.cpp:11:7: required from here
/usr/include/c++/4.7/bits/stl_list.h:115:71: error: use of deleted function 'Test::Test(const Test&)'
../../Dropbox/Programming/C++/test/main.cpp:5:7: note: 'Test::Test(const Test&)' is implicitly deleted because the default definition would be ill-formed:
../../Dropbox/Programming/C++/test/main.cpp:5: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>; std::unique_ptr<_Tp, _Dp> = std::unique_ptr<int>]'
In file included from /usr/include/c++/4.7/memory:86:0,
from ../../Dropbox/Programming/C++/test/main.cpp:3:
/usr/include/c++/4.7/bits/unique_ptr.h:262:7: error: declared here
如果您定义了~B()
,这将抑制B
的move构造函数,因此编译器将尝试生成复制构造函数,但会失败,因为unique_ptr
不是可复制构造的。
如果省略~B()
,则生成B
的move构造函数,并在main
中使用。
你可以请求自动生成的move构造函数:
B(B &&) = default;
这是标准中的一个向后兼容c++ 03代码的特性;根据三规则,编写自己的析构函数(等)的代码被认为是在管理自己的资源,因此自动生成move构造函数是不合适的,除非显式请求。
好吧,你自己说的;当提供用户定义的析构函数时,就限制了编译器生成隐式move构造函数之类的东西的能力。用户定义析构函数的内容(无论是空的还是其他的)是完全无关的。
时,将隐式声明为默认构造函数。
[C++11: 12.7/9]:
如果类X
的定义没有显式声明移动构造函数,则当且仅当:
X
没有用户声明的复制构造函数,X
没有用户声明的拷贝赋值操作符X
没有用户声明的移动赋值操作符,X
没有用户声明的析构函数和- move构造函数不会被隐式定义为删除。
[注意:当没有隐式声明或显式提供move构造函数时,否则会调用move构造函数的表达式可能会调用复制构造函数。 -end note]
注释中的文本指出了您正在看到的确切情况,导致编译失败,因为unique_ptr
无法复制;尽管您没有复制它,尽管s
的初始化可能不需要复制/移动,但该操作仍然需要可用(根据[C++11: 12.8/31-32]
)。