【问题标题】:Is it possible to prevent the destructor from running when calling delete in C++?在 C++ 中调用 delete 时是否可以阻止析构函数运行?
【发布时间】:2014-08-19 18:09:28
【问题描述】:

具体来说,在一个库中,我有一个内存池,它覆盖了某些类的 new 和 delete 行为。我希望库的用户能够对这些类的实例调用 delete,但我需要保持实例处于活动状态,直到稍后执行特定的清理操作。在让用户使用常规的 new/delete 时,这是否可能?有什么方法可以覆盖调用析构函数的默认行为?

【问题讨论】:

  • @blgt operator delete 是用于内存释放的函数和 delete 运算符之间存在差异,delete 是由编译器翻译成“析构函数调用和通过 @ 释放内存”的特殊关键字987654323@"。所以重载函数不会阻止编译器调用析构函数。
  • @ArneMertz 是的,我没有仔细阅读这个问题,这很糟糕
  • 如果你能控制这些类,我最想不到的是使用 CRTP+非虚拟析构函数的组合来实现你想要的,并从基础上做你需要的所有清理班级。不知道我是否正确理解了这个问题。
  • 只需为您的对象实施析构函数,以便在您的清理操作发生之前不删除资源
  • @EdChum,这将保留对象的资源,但不会保留对象本身。当它的析构函数运行时,对象的生命周期仍将结束,从而未定义对其的任何使用。从这个问题中不清楚这是否足以解决问题,“我需要让实例保持活动状态”意味着它不是。

标签: c++ memory-management


【解决方案1】:

简短的回答:不。 调用delete always 会触发对析构函数的调用,然后调用operator delete,就像调用new一样,先调用对应的operator new,然后运行构造函数物体。 如果你想阻止你的用户销毁对象,你必须以某种方式阻止他们 a) 对原始指针调用 delete 和 b) 在堆栈上构造它们。

如果你想让实例保持活动状态,听起来想管理它们的生命周期,所以自然的方法是首先在你的库中创建对象。此外,在代码中使用普通的delete 调用现在无论如何都被认为是不好的风格,因为有可用的智能指针可以自动执行这些调用。

所以你可以做的是向你的库中添加创建者函数来返回某种智能指针。这些可能是shared_ptrunique_ptrs,带有一个特殊的删除器,它不会真正删除对象,而是将其传递回您的库以便稍后清理。

【讨论】:

  • +1,创建者函数使用户更难创建这些类型的非托管实例,有助于确保它们始终由智能指针类型正确管理,因此将被正确处理。跨度>
  • 但是,我更愿意将shared_ptr 与自定义删除器一起使用,而不是在簿记部分中仅使用shared_ptr 的副本,否则拥有weak_ptr 的用户可以复活对象它应该已经消失并被上演进行清理。这使清理代码复杂化(它需要检查 shared_ptr 是否真的是唯一的,这在多线程程序中很难),这意味着用户可以看到这些对象的 OP 自定义生命周期(他们可以告诉对象不不是真的死,他们只是去一个更好的地方;-)
  • @JonathanWakely imo 对象的创建和销毁应该尽可能对称,这意味着两者应该以对称的方式发生在同一个地方。因此,如果我只是通过将一个对象扔进图书馆来处理它,我应该从同一个图书馆得到它。
  • @JonathanWakely 关于存储的shared_ptrs 的好点,更新了我的答案。
【解决方案2】:

使用智能指针而不是 new/delete(无论如何这是一个好习惯)。

使用自定义删除器将对象的所有权移至“等待清理”对象列表。

有关智能指针的示例,请参阅std::unique_ptrstd::shared_ptr

另一种选择(这是更多的工作和更难做到正确)是只将对象存储在使用自定义分配器的容器中,并让分配器的 destroydeallocate 函数执行“移动到暂存区清理而不是实际销毁它”部分。我会推荐使用自定义删除器方法的智能指针,而不是分配器。

这两个选项(自定义删除器和自定义分配器)都允许您控制对象被“销毁”时的确切行为,将对象生命周期的实际结束与用户处置它的那一刻分开,这是无法做到的delete 运算符。

【讨论】:

    【解决方案3】:

    delete 运行析构函数。这是每个人都依赖的基本事实。如果你能以某种方式禁用析构函数调用,而你不能,你会打破每个人的期望。如果您不希望您的用户调用析构函数,请不要让析构函数对他们可用。受保护的析构函数将使delete 不可调用。

    【讨论】:

      猜你喜欢
      • 2013-06-25
      • 2018-06-02
      • 2010-11-26
      • 1970-01-01
      • 1970-01-01
      • 2014-11-22
      • 2013-06-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多