提供(空)用户定义的析构函数会导致编译错误

jsd*_*sdw 6 c++ destructor compiler-errors unique-ptr c++11

当我没有用户定义的析构函数时,编译完全正常的代码(在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>();
}
Run Code Online (Sandbox Code Playgroud)

析构函数未注释时产生的错误中的突出点是:

  • Test的复制构造函数不存在,并且没有隐式创建,因为它会形成错误
  • 有人试图将唯一的复制构造函数用于unique_ptr.

对于任何感兴趣的人来说,完整的错误输出位于这篇文章的底部.

我知道unique_ptr不能复制构造(除非参数是一个rvalue),因此编译器不可能为该类生成有效的隐式复制构造函数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
Run Code Online (Sandbox Code Playgroud)

eca*_*mur 14

如果你定义~B(),这会抑制移动构造函数B,所以编译器会尝试生成一个复制构造函数但是因为unique_ptr不是可复制构造而失败.

如果省略~B(),B则生成并使用移动构造函数main.

您可以请求自动生成的移动构造函数:

B(B &&) = default;
Run Code Online (Sandbox Code Playgroud)

这是与C++ 03代码向后兼容的标准中的一个特性; 根据规则三,编写自己的析构函数(等)的代码被假定为管理自己的资源,因此除非明确请求,否则自动生成移动构造函数是不合适的.

  • 请注意,如果你没有落入新的*`auto`到处*趋势,只需键入`B <int> s;`就不需要定义移动或复制构造函数.我觉得有趣的是如何创建`auto`以减少打字并突然习惯输入更多... (8认同)