这是我所拥有的一些代码的简化版本。由于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;
答案 0 :(得分:2)
对于每个new
,在执行您的应用程序时,必须只有一个delete
。
因此,在析构函数中调用delete pointerB
还是在外部调用delete beta
并不重要。因为它是在这里释放的相同内存!问题是A"拥有" B的一个实例(因此负责释放它使用的内存)或者A只有一个B实例的引用(并且例如在仍然使用beta时删除)。
但是(正如Roger已经指出的那样)我建议您阅读std::shared_ptr
和std::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)
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!
你需要仔细考虑这一点。
答案 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()
完成了A
在main()
和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();
}