假设你有一个这样的简单类:
class foo{
private:
int* mData;
int mSize;
public:
foo(int size){
mSize = size;
mData = new int [mSize];
}
~foo() {
mSize = 0;
delete [] mData;
}
};
然后在主要内部你做:
int main () {
static int HUGE = 100000000;
foo a(HUGE);
// do something useful with a
// .
// .
// .
// Now I'm done with a; I do not need it anymore ...
foo b(HUGE);
// do something useful with b
// Ok we are done with b
return 0;
}
正如您所见a
之后不再需要b
,但由于它是在堆栈上创建的,因此在程序结束之前不会调用析构函数。现在,我知道这与分配new
并忘记调用delete
不同,但这仍然在浪费内存。你认为这是“内存泄漏”还是只是一个糟糕的编程?
另外,你会如何避免这样的情况?一种方法是在不再需要对象时手动调用析构函数,但是,除了看起来丑陋和不熟悉之外,你会遇到double free
的麻烦,除非你将析构函数更改为:
foo::~foo(){
if (mData != NULL){
delete [] mData;
mData = NULL;
mSize = 0;
}
}
另一种方法是通过a
在堆上创建foo *pa = new foo (HUGE)
,然后在不再需要该对象时调用delete pa
。这有效,但存在引入另一个可能的内存泄漏的危险(如果忘记调用delete pa
)。
有没有更好的方法来摆脱不需要的物品?
答案 0 :(得分:10)
当对象超出范围时,将调用析构函数。 C ++允许函数体内的任意范围。用这种方式写你的主要功能:
int main () {
static int HUGE = 100000000;
{
foo a(HUGE);
// do something useful with a
// Now I'm done with a; I do not need it anymore ...
}
{
foo b(HUGE);
// do something useful with b
// Ok we are done with b
}
// etc.
return 0;
}
我看到你的例子是简化的,但在真实的程序中,不要忘记
operator=
或foo
operator=
添加声明,因此无法调用它。答案 1 :(得分:3)
如果您担心范围,只需将巨大的a和b物体放入自己的牙套中即可。
这在技术上并不是内存泄漏,但正如你所说的那样,内存管理非常糟糕。
{
{
foo a(HUGE);
}
...
{
foo b(HUGE);
}
答案 2 :(得分:1)
不,它定义为内存泄漏。
内存泄漏是指您分配内存并丢失其句柄,因此您无法在之后释放内存。只要你这样做,在何时何地释放记忆并不重要。
您可以添加封闭范围以强制释放内存:
{
foo a(HUGE);
}
{
foo b(HUGE);
}
答案 3 :(得分:1)
这不是内存泄漏,因为不会忘记已分配的内存。然而,这稍微无效,特别是当程序运行时间更长时,应该避免使用。
您可以使用范围缩短对象的生命周期:
int main () {
static int HUGE = 100000000;
{
foo a(HUGE);
// do something useful with a
// .
// .
// .
// Now I'm done with a; I do not need it anymore ...
}
{
foo b(HUGE);
// do something useful with b
// Ok we are done with b
}
return 0;
}
此外,值得重新考虑的是,如果这两部分代码应该在单独的函数中,那么从函数返回时将释放分配的对象。
答案 4 :(得分:1)
类的构造函数也可以将您在'main()'函数中分配的内存块作为参数。这样,一旦使用内存块完成'a',你也可以将它传递给'b'。 'foo'析构函数根本不需要释放任何内存,你根本不需要担心浪费内存或对生命周期。
答案 5 :(得分:0)
你认为这是“内存泄漏”还是只是一个糟糕的编程?
不,这不是内存泄漏。
你会如何避免这种情况?
写小功能,几行。您的代码将更易读,并且将释放在堆栈上分配的未使用的变量。
答案 6 :(得分:0)
这不是内存泄漏;然而,这恰恰是Firefox开发人员花了很长时间修复的内存使用情况。
范围可能是最简单的解决方法,正如Dark Falcon所暗示的那样。或者,将分配和相关代码移动到单独的函数中。
使用std::auto_ptr
可以更安全地处理指针,以便在释放范围时释放它们。
答案 7 :(得分:0)
你认为这是“内存泄漏”
不,除非你在中间做像longjmp这样的事情。
或只是一个糟糕的节目?
我考虑使用new []在你的类糟糕的编程实践中分配数组,因为你有std :: vector。
另外,你会如何避免这种情况?
将foo包含在范围内:
{
foo a(HUGE);
}
除非您将析构函数更改为:
删除忽略空指针。析构函数只调用一次,因此不需要零变量。手动调用析构函数是VERY BAD IDEA - 它不适用于此。如果要重新初始化结构,请实现clear()或resize()方法。
有没有更好的方法来摆脱不需要的物品?
是的,将它们放在范围内。
答案 8 :(得分:0)
这不是内存泄漏,但如果你有一个你需要的变量 功能的前半部分,而不是第二部分,很有可能 函数做得很多,应该重构成两个(或者 更多)单独的功能。
答案 9 :(得分:0)
提取功能以缩小范围。给他们好名字:
void do_a(int amount)
{
foo a(amount);
// ask `a` to be useful
}
void do_b(int amount)
{
foo b(amount);
// ask `b` to be useful
}
int main () {
static int HUGE = 100000000;
do_a(HUGE);
do_b(HUGE);
return 0;
}