为什么push_back在包含unique_ptr的结构上成功,除非该结构具有自定义析构函数?

eve*_*ode 4 c++ stl c++11

当且仅当我删除Foo的自定义析构函数时,以下代码才会编译.

struct Foo {
    std::unique_ptr <int> bar;
    ~Foo (void) {} // This Line
};
std::vector <Foo> foos;
foos.push_back (Foo ());
Run Code Online (Sandbox Code Playgroud)

以下是我认为我对这种情况的理解:

它失败,因为unique_ptrs无法复制,并std::vector::push_back (thing)调用thing's复制构造函数.如果我编写Foo一个明确移动的自定义复制构造函数bar,那么一切都会好的.

但是,禁用This Line将导致代码编译.

我想,这应该无法编译,即使没有This Line,因为我仍然在尝试push_back一个unique_ptr.

为什么没有自定义析构函数就能成功,为什么添加自定义析构函数会导致它失败?

编辑:gcc -std=gnu++11在Debian Linux 64位上使用

Nat*_* S. 6

我不能保证这是你的情况下发生的事情,但它与我最近看到的事情有关:

您无法复制唯一指针,但可以移动它们.

在C++ 11中,如果没有定义析构函数,你将得到一个默认的移动构造函数,但是如果定义一个,编译器就不必提供移动构造函数,在这种情况下代码就会失败.(我知道Visual Studio不会这样做,但在我的Mac上使用Xcode我仍然得到了移动构造函数.)

所以,我认为这就是你的情况.尝试提供析构函数和其他构造函数/赋值运算符,以查看它是否修复了问题.(参见关于五条规则的讨论.)


fas*_*ked 5

根据标准"12.8.9复制和移动类对象[class.copy]"

如果类X的定义没有显式声明移动构造函数,那么当且仅当以下情况时,将隐式声明一个默认值:

  • X没有用户声明的复制构造函数,
  • X没有用户声明的复制赋值运算符,
  • X没有用户声明的移动赋值运算符,
  • X没有用户声明的析构函数,和
  • 移动构造函数不会被隐式定义为已删除.

因此,如果一个类没有用户定义的析构函数,那么将声明一个move-constructor.根据标准的"12.8.15",这将为unique_ptr类成员调用move-constructor :

非联合类X的隐式定义的复制/移动构造函数执行其基础和成员的成员复制/移动.

如果一个类具有用户定义的析构函数,则应该显式声明move-constructor:

struct Foo {
         std::unique_ptr <int> bar;

         Foo() = default;
         Foo(Foo&&) = default;

         ~Foo (void) {} // This Line
 };
Run Code Online (Sandbox Code Playgroud)