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

时间:2013-04-24 13:07:54

标签: c++ c++11 compiler-errors destructor unique-ptr

当我没有用户定义的析构函数时编译完全正常的代码(在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不能复制构造(除非参数是rvalue),因此编译器不可能为类{{1}生成有效的隐式复制构造函数}。

我无法弄清楚为什么定义一个析构函数应该突然需要这些复制工具。显然,当使用像Test这样的东西时,这是不可能提供的。

这里有人能够告诉我为什么会这样吗?

未对析构函数进行注释时完成错误输出:

unique_ptr

2 个答案:

答案 0 :(得分:14)

如果定义~B(),则会禁止B的移动构造函数,因此编译器会尝试生成复制构造函数,但会失败,因为unique_ptr不是可复制构造的。

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

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

B(B &&) = default;

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

答案 1 :(得分:3)

嗯,你自己说的;当您提供用户定义的析构函数时,您将禁止编译器生成隐式移动构造函数之类的内容。用户定义的析构函数的内容(无论是空的还是其他的)都是完全不相关的。

  

[C++11: 12.7/9]: 如果类X的定义未明确声明移动构造函数,则当且仅当

时,才会将其隐式声明为默认值      
      
  • X没有用户声明的复制构造函数,
  •   
  • X没有用户声明的副本分配运算符
  •   
  • X没有用户声明的移动分配运算符
  •   
  • X没有用户声明的析构函数
  •   
  • 移动构造函数不会被隐式定义为已删除。
  •   
     

[注意: 当没有隐式声明或显式提供移动构造函数时,否则会调用移动构造函数的表达式可能会调用复制构造函数。 - 尾注]

说明中的文字指出了您所看到的确切情况,导致编译失败,因为unique_ptr 无法被复制;虽然没有复制它,虽然s的初始化可能不需要复制/移动,但操作仍然需要可用(每[C++11: 12.8/31-32])。