【发布时间】: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