首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么push_back在包含unique_ptr的结构上成功,除非该结构具有自定义析构函数?

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

Stack Overflow用户
提问于 2014-03-01 07:16:13
回答 3查看 995关注 0票数 4

以下代码编译的当且仅当我删除Foo的自定义析构函数。

代码语言:javascript
运行
复制
struct Foo {
    std::unique_ptr <int> bar;
    ~Foo (void) {} // This Line
};
std::vector <Foo> foos;
foos.push_back (Foo ());

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

它失败了,因为unique_ptrs不能被复制,而且std::vector::push_back (thing)调用thing's复制构造函数。如果我编写Foo --一个显式移动bar的自定义复制构造函数,那么一切都会好的。

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

我认为即使没有This Line,这也不能编译,因为我仍然在尝试push_back一个unique_ptr

为什么在没有自定义析构函数的情况下这会成功,为什么添加自定义析构函数会导致它失败?

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-03-01 07:25:00

我不能保证这就是你的情况,但这与我最近看到的一些事情有关:

您不能复制唯一的指针,但可以移动它们。

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

所以,我认为这就是你的案子发生的事。尝试提供析构函数和其他构造函数/赋值运算符,以查看它是否修复了某些内容。(参见关于五条规则的讨论。)

票数 7
EN

Stack Overflow用户

发布于 2014-03-01 07:34:14

按照标准"12.8.9复制和移动类对象class.copy“

如果类X的定义没有显式声明移动构造函数,则将隐式声明为defaulted当且仅当:

  • X没有用户声明的副本构造函数,
  • X没有用户声明的复制赋值操作符,
  • X没有用户声明的移动赋值操作符,
  • X没有用户声明的析构函数,并且
  • 移动构造函数不会被隐式定义为已删除。

因此,如果类没有用户定义的析构函数,则将声明一个移动构造函数。根据标准的"12.8.15“,这将调用unique_ptr类成员的move-构造函数:

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

如果类具有用户定义的析构函数,则应显式声明移动构造函数:

代码语言:javascript
运行
复制
struct Foo {
         std::unique_ptr <int> bar;
 
         Foo() = default;
         Foo(Foo&&) = default;

         ~Foo (void) {} // This Line
 };
票数 5
EN

Stack Overflow用户

发布于 2014-03-01 07:47:27

显式析构函数使编译器不生成默认的移动构造函数和默认的分配移动运算符,这两个是unique_ptr在所有权转移中所必需的。因此,如果要实现析构函数,则必须实现这些参数:

代码语言:javascript
运行
复制
Foo(){}
Foo &operator=(Foo &&o) {
    if (this != &o)
        bar = std::move(o.bar);
    return *this;
}
Foo(Foo &&o) : bar(std::move(o.bar)) {}

因为不应该复制Foo,所以我建议只移除复制构造函数和赋值操作符:

代码语言:javascript
运行
复制
Foo(Foo const &) = delete;
Foo &operator=(Foo const &) = delete;  

编辑

实际上,五条规则更好地解释了这一点,如果您实现了以下任何一种方法,那么在google上很容易找到:

代码语言:javascript
运行
复制
destructor
copy constructor
move constructor
copy assignment operator
move assignment operator

您应该考虑实现所有这些(或删除),尤其是在使用使用移动语义的unique_ptr时。

当您注释掉析构函数时,输入零规则

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22111387

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档