【问题标题】:Implicit use of destructor隐式使用析构函数
【发布时间】:2017-12-03 13:46:16
【问题描述】:

我有一个带有已删除析构函数的类(实际上,它需要外部帮助才能被销毁):

struct indestructible {
    indestructible(indestructible&&);
    ~indestructible() = delete;
};

当我尝试使用它的移动构造函数时,编译器会报错:

struct user {
   indestructible ind;
   user(indestructible&& ind) : ind(std::move(ind)) {}
};

indestructible.cc:11:3: error: attempt to use a deleted function
user(indestructible&& ind) : ind(std::move(ind)) {}
^
indestructible.cc:6:3: note: '~indestructible' has been explicitly marked  deleted here
    ~indestructible() = delete;

发生了什么事?没有其他成员可以抛出,构造函数体也没有,那么为什么移动构造函数会调用析构函数呢?

【问题讨论】:

  • 如果indestructible不能被破坏,那么任何包含它的对象怎么会被破坏?
  • 请注意,user 的析构函数仍会尝试破坏 ind
  • 一个(稍微)比删除的析构函数更好的解决方案可能是受保护的或私有的析构函数,并且用户必须派生或成为朋友。或者,您可以设计对象,使其实际上可以具有正常的析构函数,并在构造函数中完成特殊工作
  • 用户将通过类似于 std::unique_ptr; 的方式被销毁user_destroyer::operator() 将执行清理 user 和 indestructible 所需的操作。
  • 我想避免使用私有析构函数,因为我不希望它在任何情况下都被调用——没有外部信息真的没有办法摧毁 indestructible。

标签: c++ c++11


【解决方案1】:

当您的user 对象超出范围时,它会被破坏。它的成员被破坏了,包括indestructible 成员,这是不可能的,因为它的析构函数被删除了。

【讨论】:

  • 在我的示例中,用户对象永远不会超出任何范围。考虑:auto user = new user(std::move(*new indestructible)); 所以user 的析构函数永远不会被调用。还要考虑编译器错误消息的上下文——它是user 的移动构造函数。为什么一定要在那里实例化析构函数?
  • 既然“移动”一个对象并不意味着被移动的对象不复存在。 auto a = std::move (b); 不会破坏 b。由实现移动构造函数的程序员决定它所处的状态。对于编译器,b 的生命周期在b 超出范围时结束。
  • 此外,: ind(std::move(ind)) 作用于参数ind,它是一个变量,因此在移动构造函数的末尾超出范围。因此,您甚至无需销毁 user 即可遇到问题。
  • 除了ind参数是一个引用并且销毁它是一个空操作。
【解决方案2】:

[class.base.init]/12:

在非委托构造函数中,每个直接或 虚拟基类和类类型的每个非静态数据成员 可能被调用(12.4)。 [ 注意:本条款确保 可以为完全构造的子对象调用析构函数,以防万一 抛出异常(15.2)。 —尾注 ]

[class.dtor]/11:

如果可能调用的析构函数是 从调用的上下文中删除或无法访问。

不抛出异常的构造函数也不例外。另见CWG 1915

【讨论】:

    猜你喜欢
    • 2021-11-20
    • 2016-11-15
    • 2016-12-28
    • 2012-01-23
    • 2010-10-01
    • 2020-01-21
    • 1970-01-01
    • 2016-01-02
    相关资源
    最近更新 更多