C ++指针和删除

时间:2013-06-05 06:30:01

标签: c++ pointers memory

这是我所拥有的一些代码的简化版本。由于pointerB中的class A设置为指针beta,在指向已分配内存的客户端代码中,我必须释放析构函数中pointerB指向的内存class A一旦被删除了吗?

class A{
   public:
     A(B* beta){
        pointerB = beta;
     }
     ~A(){

      /*
      would deleting pointerB be necessary
      */

      }

     B* pointerB;
};
class B{
   public:
     B();
};

//client code
B* beta = new B();
A* alpha = new A(beta);    

//do stuff
delete beta;
delete alpha;
beta = NULL;
alpha = NULL;

7 个答案:

答案 0 :(得分:2)

对于每个new,在执行您的应用程序时,必须只有一个delete

因此,在析构函数中调用delete pointerB还是在外部调用delete beta并不重要。因为它是在这里释放的相同内存!问题是A"拥有" B的一个实例(因此负责释放它使用的内存)或者A只有一个B实例的引用(并且例如在仍然使用beta时删除)。

但是(正如Roger已经指出的那样)我建议您阅读std::shared_ptrstd::unique_ptr的文档。例如:http://en.cppreference.com/w/cpp/memory在大多数情况下,您可以充分利用这些,然后您不必关心内存管理。

答案 1 :(得分:2)

类似A类型的对象看起来像是保留指向B对象的指针,但不拥有B。这很好,A的析构函数不应该尝试删除B对象。

鉴于此模型,客户端应确保指向B的构造函数的A对象在A对象的整个生命周期内保持存在。您的客户端代码无法执行此操作,但如果您完全避免动态分配对象,则实现此操作既简单又自然,并消除了泄漏对象的任何可能性。

E.g。

void client()
{
    B b;
    A a(&b);

    // do stuff

    // Because we constructed `a` after we constructed `b` in this scope
    // we are guarateed that `a` will be destroyed before `b` (reverse order)
    // and the pointer that `a` is holding will never point to a destroyed
    // object.
}

答案 2 :(得分:1)

ApointerB = beta;的构造函数中的赋值不会分配新内存。因此,在调用A的析构函数时,您无需取消分配它。

但是,这种行为有风险:

B* beta = new B(); // memory for B is allocated
A alpha( B ); // local instance. A.pointerB points to beta
delete beta; // memory de-allocated
// risky part: alpha.pointerB still points to where beta was allocated 
// BUT THIS MEMORY IS ALREADY FREED!

你需要仔细考虑这一点。

答案 3 :(得分:0)

您的示例可以简化为:

struct A{};

int main()
{
  A* wtf= new A;
  A* omg= wtf;
  delete wtf;
}

是正确的,所以:

struct A{};

int main()
{
  A* wtf= new A;
  A* omg= wtf;
  delete omg;
}

删除两者都是双删除错误,请勿执行此操作:

delete omg;
delete wtf;

你会尝试释放两个指针指向的相同内存,两次!

答案 4 :(得分:0)

当你动态分配内存时,你必须释放它。

执行 new B() 时,您可以动态分配对象的内存,然后将地址分配给类型为beta的{​​{1}}。这是指向该内存的指针。执行B*时,删除已分配的内存。许多指针(如构造函数中的指针)可以指向此内存但是您只需要删除一次。但是如果你试图使用其他指针(取消引用等),你可以吹掉你的代码。

只有当你执行delete beta时才分配内存。 [您的代码必须包含必须发布的new]的相等和相应数量

考虑这种方式,你有一个存储数据的地方和几个指向该地点位置的标签。现在,如果使用一个标签销毁该地点,其他标签仍将具有该位置。但现在它没用了,因为这个地方现在已经不存在了。

答案 5 :(得分:0)

整个想法是,如果你从堆中分配一些东西,你应该释放它,它应该只进行一次,而且,你应该在取消分配之后访问内存。

为了实现这一点,我们通常会通过相同的组件进行分配和解除分配。例如,如果在Foo类中分配一块内存,那么也要在那里进行释放。但是,使事情不那么容易出错只是一种惯例。只要你确定释放将要发生,并且只发生一次,一切都很好。

使用shared_ptr或类似工具也是确保此行为的一种方法。

回到你的具体例子,我们不能说你是否应该在A中进行解除分配。我可以说的是,如果你已经delete beta main()完成了Amain()A中取消分配,这是一个问题。

是否应该在{{1}}中取消分配或将其留给来电者取决于您的设计。

答案 6 :(得分:0)

你必须在A的析构函数中删除它。有一个示例程序可以测试两个条件 1.运行程序仍然存在b值存在意味着你必须在A的析构函数中删除它。 2.取消注释代码中的delete b行,您将看到b是免费的。

class B;
class A
{
    B * b;

public:
    A(B * obj)
    {
        b = obj;
    }

    ~A()
    {
        //delete b;
    }

};
class B
{
    int value;
public:
    B()
    {
        value = 10;
    }
    ~B()
    {

    }
    int getValue(){return value;}
};

void main()
{
    B *b = new B;
    A * a = new A(b);

    delete a;
    cout<<"B exists: "<<b->getValue();
}