假设我有一个班级:
class ClassX{
private:
int* p;
int i;
....
}
我在某处:
ClassX x;
.....
//and in a friend function or in a ClassX function
p = (int*) malloc (.....);
然后当x
退出其范围时,调用析构函数;但它没有释放malloc
权限分配的内存吗?
如果我重新定义它:
ClassX::~ClassX(){ delete [] p; }
它释放了malloc
分配的内存,但没有释放为类字段分配的内存(即i
和p
)?
我错过了什么吗?
谢谢。
答案 0 :(得分:3)
简单的规则是:对于每个malloc
,必须只有一个free
;对于每个new
,必须只有一个delete
;对于每个new[]
,必须只有一个delete[]
。
回答你的问题:
[析构函数]没有释放malloc分配的内存吗?
正确。它不是。在这种情况下,您调用了malloc
,但从未调用free
。
[修改后的析构函数]释放malloc分配的内存,但不释放为类字段分配的内存?
错误。它不释放内存(在这种情况下,您必须使用free
,而不是delete[]
。free
是malloc
的合作伙伴。delete[]
是{{1}合作伙伴。你无法切换合作伙伴。)
同样错误的是,它释放了为类的字段分配的内存(假设字段是非指针类型。)在析构函数返回后,释放对象占用的内存。
我错过了什么吗?
如果您要使用原始指针,还需要了解Rule of Three。但是,更好的是,永远不要使用原始指针。使用smart pointer或container。
答案 1 :(得分:3)
首先,请记住以下事项:
malloc
分配的内容需要free
malloc
new
分配的内容必须由delete
new[]
分配的内容必须由delete[]
delete
一个new
,每个delete[]
一个new[]
然后,您认为没有析构函数,malloc
分配的内存将不会被释放,这是正确的。如果您遵循上述规则,则需要使用free
(不delete[]
)来解除分配:
ClassX::~ClassX() { free(p); }
但是,您首先不应该在C ++中使用malloc
,因为它不会调用对象的构造函数,您应该使用new
:
ClassX::ClassX() : p(new int) { }
// NOW we use delete since we used new (not delete[] since we didn't use new[])
ClassX::~ClassX() { delete p; }
但是,如果这样做,则必须编写复制构造函数,复制赋值运算符,移动构造函数和移动赋值运算符。那么让我们看一个更好的方法:
class ClassX{
private:
ClassX();
std::unique_ptr<int> p;
int i;
....
};
// we have to break rule #6 here
ClassX::ClassX() : p(new int) { }
现在你甚至不必写一个析构函数,你可以让智能指针为你处理它,因为它会自动调用你delete
所做的事情的new
。析构函数被称为。这导致我们......
它释放了malloc分配的内存,但没有释放为类'字段分配的内存(即i和p)?
这大约是正确的1/4。由于i
和p
是该类的成员,因此在取消分配封闭类时会自动释放它们,如果它们是类本身,他们的析构函数将被称为。因此,如果你将delete
放在你的析构函数中,它会处理new
分配的内存,i
和p
会自动清理,一切都很好。 (你只有1/4正确,因为你使用了错误的释放函数。)
这意味着,如果您使用智能指针,则在您的对象被销毁时将调用智能指针的析构函数,并且它将自动释放您为new
分配的内容。所以你甚至不用担心它。
这是假设您真的希望将动态int
作为您班级的一部分。但是,如果你可以,你宁愿存储int
的值(不存储它的指针),这样你就不必乱用智能指针,释放或任何其他东西。
答案 2 :(得分:1)
如果你手动分配内存,你必须释放它,它不会自动为你释放。
如果您致电malloc
(或calloc
或realloc
),则需要free
该内存。同样,如果您new
某事delete
,new[]
必须与delete[]
匹配。
话虽这么说,你是用C ++编程的,并且很少有理由手动管理内存。使用智能指针,std::shared_ptr用于共享所有权,std::unique_ptr用于其他方式。
然后你的班级看起来像这样:
#include <memory>
class ClassX{
private:
std::unique_ptr<int> p;
int i;
....
};
ClassX::ClassX() : p( new int ) {} /* No need to deallocate p manually */
请注意,unique_ptr
对数组也有部分特化,所以如果p
指向数组,则可以按如下方式分配内存:
class ClassX{
private:
std::unique_ptr<int[]> p;
int i;
....
};
Class::ClassX() : p ( new int[10] ) {}
您也可以完全忘记处理指针并使用std::vector
或std::array
,尤其是对于像int数组这样简单的事情。
答案 3 :(得分:1)
你的析构函数应该释放p是正确的,但如果你用malloc
分配,你应该用free
释放内存。或者你可以用以下内容分配内存:
x.p = new int[size];
这意味着你的delete[] p
;析构函数是正确的。
关于类的成员变量,您不必担心删除它们,如果您的对象是在堆栈上分配的,它们将在堆栈展开时被删除。如果您的类已在堆上分配,则在delete x;
时将删除它们。无论哪种方式,它们的生命周期都与包含它们的对象相关联。
答案 4 :(得分:1)
为了简化,我总是告诉自己指针只是一个整数。 (根据系统的不同,它可以是16,32或64位长)。它是一个特殊的整数,有助于定义一个地址,但它只是一个整数。
因此,当您构造类X时,它会为两个“整数”分配空间。一个叫做p,另一个叫做i。当类被破坏时,它会释放两个整数和一些东西的空间。
析构函数不会打扰您使用特殊整数p(表示地址)的值。您可以像创建内存一样创建内存,或者创建一个随机数:它在表示类X的内存中完全相同:只是一个整数。
答案 5 :(得分:1)
规则很简单:
new
的内存应使用delete
释放。new []
的内存应使用delete []
释放。malloc()
的内存应使用free()
释放。请注意,您需要将分配函数返回的完全相同的地址传递给解除分配函数。
良好做法:
malloc
和free
,除非你有充分的理由,否则不要使用它们,此外,在您的情况下,您还需要关注 Rule of Three ,以便您的程序正常运行。