1

这是我拥有的一些代码的简化版本。由于pointerBinclass 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;
4

7 回答 7

2

对于每一个,在您的应用程序执行期间new都必须有一个,而且只有一个。delete

所以无论delete pointerB是在析构函数delete beta中调用还是在外部调用都没有关系。因为这里释放的是同一个内存!问题是 A 是否“拥有” B 的实例(因此负责释放它使用的内存),或者 A 是否仅引用 B 的实例(例如,在仍然使用 beta 时被删除)。

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

于 2013-06-05T06:57:03.207 回答
2

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

鉴于此模型,客户端应确保B通过指向构造函数的指针传递的对象在对象A的整个生命周期内保持存在A。您的客户端代码无法做到这一点,但如果您完全避免动态分配对象,那么实现这一点是简单而自然的,并且消除了任何泄漏对象的可能性。

例如

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.
}
于 2013-06-05T07:02:55.913 回答
1

A:的构造函数中的赋值pointerB = 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!

你需要仔细考虑这一点。

于 2013-06-05T06:39:09.277 回答
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;

您将尝试释放两个指针指向的相同内存两次!

于 2013-06-05T06:37:29.963 回答
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();
} 
于 2013-06-05T07:47:23.803 回答
0

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

当您这样做时,new B()您为对象动态分配内存,然后分配beta类型为的地址B*。这是指向该内存的指针。当你这样做时delete beta,你删除了分配的内存。该内存可以由许多指针(如构造函数中的指针)指向,但您只需删除一次。但是,如果您尝试使用其他指针(取消引用等),您可能会破坏您的代码。

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

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

于 2013-06-05T06:40:57.330 回答
0

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

为了实现这一点,我们通常使分配和释放由同一个组件完成。例如,如果您在 Foo 类中分配了一块内存,也可以在那里进行释放。但是,这只是一种让事情不易出错的约定。只要您确定释放将发生,并且只发生一次,一切都很好。

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

回到您的具体示例,我们不能说您是否应该在 A 中进行解除分配。我可以说的是,正如您已经delete beta在您所做的那样main(),如果您同时进行解除分配Amain()那么这是一个问题。

您是否应该取消分配A或将其留给调用者取决于您的设计。

于 2013-06-05T06:47:55.197 回答