在派生类中重写运算符 new/delete

发布于 2024-11-16 11:28:19 字数 1071 浏览 2 评论 0原文

我有一个无状态的抽象基类,各种具体类都从中继承。其中一些派生类也是无状态的。因为其中许多是在运行期间创建的,所以我希望通过重写运算符 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 添加与 new/delete 重载相同的技巧来解决。但我不确定这是最干净的解决方案,甚至是正确的解决方案(valgrind 不会抱怨,FWIW)。我很感激建议或批评。

编辑:实际上,情况更糟。正如我所说,这个例子中的基类不是抽象的。如果通过添加纯虚方法将其抽象化,那么我将无法再应用 new/delete 重写技巧,因为我不能拥有 Base 类型的静态变量。所以我对这个问题没有任何解决办法!

I have a stateless, abstract base class from which various concrete classes inherit. Some of these derived classes are stateless as well. Because many of them are created during a run, I'd like to save memory and overhead by having all stateless derived classes emulate a singleton, by overriding operator new()/delete(). A simplified example would look something like this:

#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;
}

This example doesn't work: delete s2; fails because delete s1; called ~Base(), which deallocated the shared Base in d2. This can be addressed by adding the same trick with new/delete overloading to Base. But I'm not sure this is the cleanest solution, or even a correct one (valgrind doesn't complain, FWIW). I'd appreciate advice or critique.

edit: actually, the situation is worse. The Base class in this example isn't abstract, as I claimed. If it's made abstract, through the addition of a pure virtual method, then I can no longer apply the new/delete overriding trick, because I cannot have a static variable of type Base. So I don't have any solution for this problem!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

蓝色星空 2024-11-23 11:28:19

你就是不能这样做 - 这会违反“对象身份”要求,该要求规定每个对象必须有自己的地址 。您必须为每个对象分配不同的内存块 - 如果您重写operator new 以使用专门为固定大小的对象定制的快速块分配器,则可以相当快地完成此操作。

You just can't do that - that would violate "object identity" requirement that states that each object must have its own address. You have to allocate distinct memory block to each object - this can be done rather fast if you override operator new to use a fast block allocator specifically tailored for objects of fixed size.

浅浅淡淡 2024-11-23 11:28:19

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

I would say the best solution here is to make your derived class an actual singleton. Make your derived constructor private and just provide a static Base* getInstance() method that either creates the required object or returns the static instance. This way the only way to get a D1 object would be via this method since calling new D1 would be illegal.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文