如何在C ++中清理已删除的对象

时间:2009-05-18 23:25:44

标签: c++

是否可以将C ++中已删除对象的内存清零?我想这样做是为了在单元测试中重现一个coredump:

//Some member variable of object-b is passed-by-pointer to object-a
//When object-b is deleted, that member variable is also deleted
//In my unit test code, I want to reproduce this
//even if I explicitly call delete on object-b
//accessBMemberVariable should coredump, but it doesn't
//I'm assuming even though object-b is deleted, it's still intact in memory
A *a = new A();
{
  B *b = new B(a);
  delete b;
}
a->accessBMemberVariable();

7 个答案:

答案 0 :(得分:20)

您可能应该覆盖delete运算符。

给定B类的例子:

class B
{
public:

  // your code
  ...

  // override delete
  void operator delete(void * p, size_t s)
  {
    ::memset(p, 0, s);
    ::operator delete(p, s);
  }
};

编辑:感谢 litb 指出这一点。

答案 1 :(得分:3)

  

accessBMemberVariable应该是coredump,但它不是

不,为什么要这样? b以前占用的内存很可能现在归CRT所有,CRT是应用程序拥有的CRT。 CRT可以选择不将内存释放回操作系统。只有在访问应用程序拥有的内存而非时,才会发生核心转储。

将b占用的内存归零可能对你有任何好处,具体取决于A具有地址的变量类型。

我的建议是在堆叠上分配B,这应该能够带出烟花......但是再一次,不是你期望的那种......

因此,如果你真的想要一个核心转储,你应该使用OS函数分配内存并释放它:

char *buf = OS_Alloc(sizeof(B));
B *b = new(buf) B();
a->someBMember = &b->myMember;
b->~B();
OS_Free(buf);
a->accessBMemberVariable();

答案 2 :(得分:2)

另一张海报建议:

 delete b;
 memset(b,0,sizeof(B));

请不要这样做!!!对返回到内存管理器的地址空间的写入是UNDEFINED !!!!

即使您的编译器和库让您现在就可以使用它,也不错。库或平台的更改,甚至是编译器中的更新都会让你感到厌烦。

考虑一个竞争条件,你删除b,然后一些其他线程进行分配,b的内存被给出,然后你调用memset!砰,你死了。

如果您必须清除内存(关心的人),请在调用delete之前将其清零。

 memset(b,0,sizeof(B));
 delete b;

答案 3 :(得分:2)

如果可以,请使用展示位置“new”(http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10) 并且在手动调用对象析构函数后将你给出的块清零。

答案 4 :(得分:1)

使用环境中的调试malloc / new功能。

在MSVC上,链接调试运行时库。在FreeBSD上,根据需要将MALLOC_OPTIONS设置为具有“Z”或“J”标志。在其他平台上,阅读文档或在具有调试支持的适当分配器中替换。

删除后调用memset()在很多级别上都是坏的。

答案 5 :(得分:0)

在你的例子中写下

'A-> accessBMemberVariable'这是一个错字?不应该是'a-> accessBMemberVariable'?

假设这是一个错字(否则整个设计看起来有点奇怪)。

如果你想验证'a'是否被正确删除,那么改为处理分配的方式并改为使用auto_ptr可能更好。这样你就可以确保删除的东西正确删除了:

auto_ptr<A> a( new A );
{
  auto_ptr<B> b( new B(a) ); // B takes ownership of 'a', delete at scope exit
}
a->accessBMemberVariable(); // shouldn't do to well.

形式的B的构造函数
B( auto_ptr<A>& a ) : m_a(a) {;}

其中

auto_ptr<A> m_a

答案 6 :(得分:-3)

删除b后,您实际上没有权限写过它的位置。但是你通常可以做到这一点;并且你会看到代码使用memset的代码。


但是,批准的方法是直接调用析构函数,然后在内存上写入(例如memset),然后在对象上调用delete。这确实需要你的析构函数非常聪明,因为delete将调用析构函数。所以析构函数必须意识到整个对象只不过是0而没有做任何事情:

b->~B();
memset(b, 0, sizeof(b));
delete b;