问题:
有没有什么方法可以让删除行为像假人一样,即在调用时什么都不做?
为什么我需要答案:
我正在使用一个自定义内存池,当调用静态方法Pool::freeAllObjects()
时,它会从内存中释放所有对象。
所有类都有一个重载的运算符new,如下所示:
void * operator new (size_t size)
{
void * obj = Pool::memory()->allocate(size);
Pool::memory()->save_destructor((ClassName*)obj);
return obj;
}
Pool::memory()->save_destructor()
只保存一个指向运行泛型类型析构函数的函数的指针。
如果没有人在使用池创建的对象上调用delete
,那么一切都行为正常但在我们想要使用它的代码中有许多对象被delete
调用,所以为了向后兼容,我试图像这样重载delete
void operator delete(void*) {/*do nothing*/}
在使用new
重载Pool::memory()
的类中
,但看起来并没有解决问题。我使用一个简单的std :: cout来查看被调用的cons /析构函数和一个重载删除,如:
void operator delete(void*) {std::cout << "deleting ClassName" << std::endl;}
所以在这样的代码中:
ClassName * instance = new ClassName();
instance->runMethod();
delete instance; //this is legacy code calling delete before the pool was developed
/*
other code goes here
*/
Pool::freeAllObjects(); // oops instance was already deleted
我得到以下输出:
constructing ClassName
&lt; - 名为
destructing ClassName
&lt; - 因调用delete而被调用的析构函数
deleting ClassName
&lt; - 删除显示其消息
destructing ClassName
&lt; - 因为Pool :: freeAllObjects在对象上运行析构函数而被调用的析构函数
编辑: 对不起,我没有提到要求不是使用智能指针并使操作员删除私有(我认为顺便说一句,这是最好的选择)也是不允许的。
答案 0 :(得分:2)
您无法阻止delete
调用析构函数;那是
它能做什么。但是因为你抓住了operator delete
稍后调用的函数,可以使用某种隐藏
旗。类似的东西:
union MemoryHeader
{
bool hasBeenDeleted;
double forAlignment;
};
void* operator new ( size_t size )
{
MemoryHeader* hdr = static_cast<MemoryHeader*>(
Pool::memory()->allocate( size + sizeof( MemoryHeader ) ) );
hdr->hasBeenDeleted = false;
void* obj = hdr + 1;
Pool::memory()->save_destructor( (ClassName*)hdr );
return obj;
}
void operator delete( void* obj )
{
MemoryHeader* hdr = static_cast<MemoryHeader*>( obj ) - 1;
hdr->hasBeenDeleted = true;
}
然后,当您运行删除时,您可以检查标记。
或者甚至更好,在你的情况下;在operator delete
function,只需取消注册对象的析构函数:add
clear_destructor
返回的Pool::memory()
函数,
并称之为。
答案 1 :(得分:1)
operator delete
是解除分配函数。
删除表达式首先调用析构函数,然后调用相关的释放函数。
“Pool :: memory() - &gt; save_destructor()只保存一个指向运行泛型类型的析构函数的函数的指针。”是一种不合时宜的设计。相反,如果要共享解除分配责任,则使用 std::shared_ptr
处理更高级别(您可以通过生成{{1}的函数将您的类限制为仅可实例化}})。这就是std::shared_ptr
的用途。
由于分配器负责销毁对象,因此高级别和低级别的问题会混淆,从而导致复杂性和可能的错误。
将这些问题分开,例如通过使用std::shared_ptr
,您可以获得更简单,更可靠的设计,这也将更符合C ++语言中的这种分离。
Andrei Alexandrescu的经典着作“Modern C ++ Design”详细讨论了如何实现自定义分配方案。您可以在Loki库中找到该分配器。我相信它是开源的。
如果您想要类似Java的自动垃圾收集,那么您可以使用Boehm收集器。我知道有些人在大中型项目中成功使用过它。但是,我没有直接的经验,但检查一下,如果那是你的目标。
答案 2 :(得分:0)
如果你想避免自动调用析构函数,你必须实现placement new
运算符,如果必须显式调用析构函数(参考C++ FAQ)。
如果你想通过delete
语句禁用释放内存,重载它是一个好主意,无论是全局(如果你知道你正在做什么)还是每个类(使用继承可能。{{1} } / new
运算符是继承的)。
这完全取决于您想要达到的目标以及您必须维持的与现有系统的兼容性。
无论哪种方式 - 它都可以。其他问题是 - 它是应该做的方式。
答案 3 :(得分:0)
您可以考虑的另一种方法是禁止对相关类使用delete
。
只需创建析构函数protected
或private
,然后将池分配器添加为friend
。
此通过添加更多复杂性或更改设计来强制执行现有设计,而不是支持错误使用(另一个答案)更简单和干净的东西(我的另一个答案)。