【问题标题】:Overriding operator new/delete in derived class在派生类中重写运算符 new/delete
【发布时间】:2011-06-22 04:54:07
【问题描述】:

我有一个无状态的抽象基类,各种具体类都从该基类继承。其中一些派生类也是无状态的。因为它们中的许多是在运行期间创建的,所以我想通过重写 operator new()/delete() 让所有无状态派生类模拟一个单例来节省内存和开销。一个简化的示例如下所示:

#include <memory>

struct Base {
  virtual ~Base() {}
 protected:
  Base() {}   // prevent concrete Base objects
};

struct D1 : public Base {  // stateful object--default behavior
  int dummy;
};

struct D2 : public Base {  // stateless object--don't allocate memory
  void* operator new(size_t size)
  {
    static D2 d2;
    return &d2;
  }
  void operator delete(void *p) {}
};

int main() {
  Base* p1 = new D1();
  Base* p2 = new D1();
  Base* s1 = new D2();
  Base* s2 = new D2();
  delete p1;
  delete p2;
  delete s1;
  delete s2;
  return 0;
}

此示例不起作用:delete s2; 失败,因为delete s1; 调用了~Base(),它释放了d2 中的共享Base。这可以通过向 Base 添加具有新/删除重载的相同技巧来解决。但我不确定这是最干净的解决方案,甚至是正确的解决方案(valgrind 不会抱怨,FWIW)。我会很感激建议或批评。

编辑:实际上,情况更糟。正如我所声称的,此示例中的 Base 类不是抽象的。如果通过添加纯虚方法使其抽象化,那么我将无法再应用新/删除覆盖技巧,因为我不能拥有 Base 类型的静态变量。所以我对这个问题没有任何解决方案!

【问题讨论】:

  • 您是否实际测量过这个“技巧”为您节省了多少内存?
  • 为什么要对无状态对象使用new
  • @Bo Persson:即使对象是无状态的,它也可以具有特定类型,并且具有不同类型的不同对象可能很重要。
  • @Martinho Fernandes:您能否详细说明为什么没有数据成员的对象不是无状态的?
  • @Eitan:重载new/delete 仅处理内存分配/释放。相应的构造函数/析构函数调用由编译器自动生成。所以如果有Base* s1 = new D2(); Base* s2 = new D2();这样的语句,分配给D2的内存会被构造两次,而不会破坏之前构造的D2对象。除非 D2 是普通旧数据,否则这将导致问题。

标签: c++ memory-management singleton overriding new-operator


【解决方案1】:

你不能这样做 - 这将违反声明 each object must have its own address 的“对象身份”要求。您必须为每个对象分配不同的内存块 - 如果您覆盖 operator new 以使用专门为固定大小的对象定制的快速块分配器,这可以相当快地完成。

【讨论】:

  • 感谢您的链接——这是一个很好的主题。我认为这个问题和我的问题之间的细微差别是我确实希望从 D2::operator new() 返回的所有对象都是同一个对象。正如我上面提到的,将其实现为单例或单独的创建/解除分配方法可以正常工作,但我希望以一种不那么杂乱无章的方式来实现(使用 new()/delete() 可以说是这样)
【解决方案2】:

我想说这里最好的解决方案是让你的派生类成为一个真正的单例。将您的派生构造函数设为私有,只需提供一个静态 Base* getInstance() 方法,该方法要么创建所需的对象,要么返回静态实例。这样获取 D1 对象的唯一方法就是通过这个方法,因为调用 new D1 是非法的。

【讨论】:

  • 我实际上是从类似的东西开始的。然而,我没有使用 getInstance(),而是在每个派生类中使用了 create() 方法(和 deallocate()),该方法返回指向相应类型对象的指针,该对象将在有状态对象中被 new 并在无国籍者。这工作得很好,但我想知道我是否可以使用语言机制(即 new() 和 delete())使这个更干净。
  • 使用语言机制并不干净,因为许多人在使用这些时会做出某些断言,并且这些断言(例如 new 确实分配了一个新对象,并且使用 new 创建的 2 个对象的地址比较不相等) .甚至方法名称create 也可能造成这些误解,所以我会选择getrelease,或者在每次用户需要时简单地分配一个新的无状态对象,这不应该是一个问题,除非它们用于非常性能关键代码部分。
  • @smerlin:感谢您深入了解用户期望。我认为您的命名方案更好。至于性能,我对其进行了测量并在较早的评论中发布,这个技巧的效果是减少了大约 25% 的整体应用程序运行时间,非常重要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-12
  • 2012-08-04
  • 2014-03-26
  • 2011-08-06
  • 1970-01-01
相关资源
最近更新 更多