检查未解除分配的指针

时间:2012-06-22 09:46:19

标签: c++ pointers memory-management

假设正在一个点上分配指针对象,并且它正被返回到不同的嵌套函数。有一次,我想在检查它是否有效或已被某人解除分配后取消分配该指针。

是否有任何保证可以使用?

if(ptr != NULL)
   delete ptr;

OR

if(ptr)
   delete ptr;

此代码不起作用。它总是给出分段错误

#include <iostream>
class A
{
    public:
    int x;
     A(int a){ x=a;}
     ~A()
     { 
          if(this || this != NULL) 
              delete this;
     }
};
int main()
{ 
    A *a = new A(3);
    delete a;
    a=NULL;
}

修改

每当我们谈论指针时,人们就开始问,为什么不使用Smart Pointers。 仅仅因为智能指针存在,每个人都无法使用它。

我们可能正在使用旧式指针的系统。我们无法将所有这些转换为智能指针,一个晴朗的日子。

5 个答案:

答案 0 :(得分:6)

  

if(ptr != NULL) delete ptr;

     

OR

     

if(ptr) delete ptr;

这两个实际上是等价的,也与delete ptr;相同,因为在delete指针上调用NULL可以保证工作(因为,它什么都不做)。

如果ptr是悬空指针,则无法保证它们正常工作。

含义:

int* x = new int;
int* ptr = x;
//ptr and x point to the same location
delete x;
//x is deleted, but ptr still points to the same location
x = NULL;
//even if x is set to NULL, ptr is not changed
if (ptr)  //this is true
   delete ptr;   //this invokes undefined behavior

在您的特定代码中,您将获得异常,因为您在析构函数中调用delete this,而析构函数又会再次调用析构函数。由于this永远不会NULL,因此析构函数将无法控制递归,因此您将获得STACK OVERFLOW。

答案 1 :(得分:4)

不要在析构函数中调用delete this

  

5.3.5,删除:如果delete-expression的操作数值不是空指针值,则delete-expression将   为对象或要删除的数组的元素调用析构函数(如果有)。

因此,你将在析构函数中有无限递归。

然后:

if (p)
    delete p;

检查p是否为空(C ++中的if (x)表示if x != 0)是多余的。 delete已做过检查。

这是有效的:

class Foo {
public:
    Foo () : p(0) {}
    ~Foo() { delete p; }
private:
    int *p;

    // Handcrafting copy assignment for classes that store 
    // pointers is seriously non-trivial, so forbid copying:
    Foo (Foo const&) = delete;
    Foo& operator= (Foo const &) = delete;
};

不要假设任何内置类型(如intfloat或指向某事物的指针)要自动初始化,因此,如果没有明确初始化它们,请不要认为它们是0 (只有全局变量将被零初始化):

  

8.5初始值设定项:如果没有为对象指定初始化程序,则默认初始化该对象;如果没有执行初始化,则   具有自动或动态存储持续时间的对象具有不确定的值。 [注意:具有静态或线程存储持续时间的对象是零初始化

所以:始终初始化内置类型!


  

我的问题是我应该如何避免双重删除指针并防止崩溃。

应该输入析构函数并将其保留一次。不是零次,不是两次,一次。

如果您有多个可以到达指针的地方,但不确定何时允许删除,即如果您发现自己有记账,请使用更简单的算法,更简单的规则或智能指针,例如{ {1}}或std::shared_ptr

std::unique_ptr

答案 2 :(得分:2)

在有人删除指针后,您无法假设指针将设置为NULL。 embarcadero C ++ Builder XE就是这种情况。之后它可能会设置为NULL但不要使用不允许您的代码再次删除它的事实。

答案 3 :(得分:0)

你问:“在某一点上,我想在检查它是否有效或已被某人解除分配后取消分配该指针。”

在C / C ++中有没有可移植的方法来检查&gt;裸指针&lt;是否有效。而已。在那里结束了故事。 你不能这样做。再次:只有你使用或C风格的指针。还有其他类型的指针没有这个问题,所以为什么不使用它们呢!

现在问题变成了:为什么你坚持你应该使用裸指针?不要使用裸指针,适当地使用std::shared_ptrstd::weak_ptr,你甚至不必担心删除任何东西。当最后一个指针超出范围时,它会自动删除。以下是一个例子。

示例代码显示堆上分配了两个对象实例:一个整数和一个Holder。当test()返回时,调用者std::auto_ptr<Holder>不使用返回的main()。因此,指针被破坏,从而删除了Holder类的实例。当实例被破坏时,它会将指针析构为整数的实例 - 指向该整数的两个指针中的第二个。然后myInt也被破坏,因此最后一个指向整数的指针被破坏,内存被释放。自动且无后顾之忧。

class Holder {
  std::auto_ptr<int> data;
public:
  Holder(const std::auto_ptr<int> & d) : data(d) {}
}

std::auto_ptr<Holder> test() {
  std::auto_ptr<int> myInt = new int;
  std::auto_ptr<Holder> myHolder = new Holder(myInt);
  return myHolder;
}

int main(int, char**) {
  test(); // notice we don't do any deallocations!
}

不要在C ++中使用裸指针,没有充分的理由。它只能让你在脚下射击自己。多次。放弃;)

智能指针的粗略指导原则如下:

  • std :: auto_ptr - 当范围是对象的唯一所有者时使用,并且范围终止时对象的生命周期结束。因此,如果auto_ptr是一个类成员,那么当类的实例被销毁时,指向对象的删除必须有意义。将其用作函数中的自动变量也是如此。在所有其他情况下,请勿使用它。

  • std :: shared_ptr - 它的使用意味着所有权,可能在多个指针之间共享。指向对象的生命周期在它的最后一个指针被销毁时结束。管理对象的生命周期非常简单,但要注意循环引用。如果Class1拥有Class2的实例,并且Class2的同一个实例拥有Class1的前一个实例,那么指针本身将不会删除这些类。

  • std :: weak_ptr - 其使用意味着非所有权。它不能直接使用,但必须在使用前转换回shared_ptrweak_ptr不会阻止对象被破坏,因此它不会出现循环引用问题。它是安全的,因为它悬挂时你不能使用它。它会断言或向您显示空指针,从而导致立即发生段错误。使用悬空指针更糟糕,因为它们似乎经常起作用。

    这实际上是weak_ptr的主要好处:使用裸C风格的指针,你永远不会知道是否有人删除了这个对象。 weak_ptr知道最后shared_ptr何时超出范围,并且会阻止您使用该对象。您甚至可以询问它是否仍然有效:如果对象被删除,expired()方法将返回true

答案 4 :(得分:-1)

你永远不应该使用delete this。由于两个原因,析构函数正在删除内存并使您有机会整理(释放OS资源,删除对象创建的对象中的任何指针)。其次,对象可能在堆栈中。