我在这里正确使用删除吗?

时间:2010-03-03 16:54:09

标签: c++ class memory-management delete-operator

我刚刚开始结合我对C ++类和动态数组的了解。我得到了“任何时候我使用新运算符”的建议我应该删除。我也知道析构函数是如何工作的,所以我认为这段代码是正确的:

的main.cpp

...
int main()
{
    PicLib *lib = new PicLib;
    beginStorage(lib);
    return 0;
}

void beginStorage(PicLib *lib)
{
...
    if (command != 'q')
    {
        //let's assume I add a whole bunch
            //of stuff to PicLib and have some fun here
        beginStorage(lib);
    }
    else
    {
        delete lib;
        lib = NULL;
        cout << "Ciao" << endl;
    }
}

PicLib.cpp

...

PicLib::PicLib()
{
    database = new Pic[MAX_DATABASE];
    num_pics = 0;
}

PicLib::~PicLib()
{
    delete[] database;
    database = NULL;
    num_pics = 0;
}
...

我用Pic类填充我的PicLib,其中包含更多动态数组。 Pic的析构函数以与上面相同的方式删除它们。我认为delete [] database正确地摆脱了所有这些类。

那么 main.cpp 中的删除是否必要?一切看起来都很笨拙吗?

8 个答案:

答案 0 :(得分:5)

有几个问题:

int main() 
{ 
  PicLib *lib = new PicLib; 
  beginStorage(lib); 
  return 0; 
}

最好在同一范围内分配和删除内存,以便轻松发现。

但在这种情况下,只需在本地声明(并通过引用传递):

int main() 
{ 
    PicLib  lib; 
    beginStorage(lib); 
    return 0; 
}

在beginStorage()

但我认为没有理由操纵指针。通过引用传递它,并在本地使用它。

void beginStorage(PicLib& lib)
{
 ....
}

在PicLib类中,您有一个RAW指针:数据库。

如果你有一个你拥有的RAW指针(你创建并销毁它),那么你必须覆盖复制构造函数和赋值运算符的编译器生成版本。但在这种情况下,我认为没有理由选择一个指针,使用矢量会更容易:

class PivLib
{
    private:
        std::vector<Pic>   databases;
};

答案 1 :(得分:3)

是的,使用删除删除 new 创建的任何内容,以及使用 new [] 删除[] 删除必须

我会在你的代码中指出一些事情:

  • 首选std :: vector&lt;&gt;过度使用new []和delete []。它会为你做内存管理。还要看一下智能指针,如auto_ptr,shared_ptr和C ++ 0x unique_ptr,用于自动内存管理。这些有助于避免忘记删除并导致内存泄漏。如果可以,请不要使用new / new [] / delete / delete []!
  • 如果你必须新建并删除一些内容,那么在类构造函数中新建 非常好主意,并在类析构函数中删除。抛出异常时,对象超出范围等,它们的析构函数会自动调用,因此这有助于防止内存泄漏。它被称为RAII。
  • beginStorage 删除其参数可能是一个坏主意。如果使用不是使用 new 创建的指针调用该函数,它可能会崩溃,因为您无法删除任何指针。如果 main()在堆栈上创建PicLib而不是使用new和delete,并且beginStorage可以获取引用而不删除任何内容,那就更好了。

答案 2 :(得分:2)

是的,这是必要的,除非你使用auto_ptr(并在使用之前阅读auto_ptr的语义 - 你不能复制它)。

例如:

int main()
{
    auto_ptr<PicLib> lib = new PicLib;
    beginStorage(lib);
    return 0;
} // auto_ptr goes out of scope and cleans up for you

答案 3 :(得分:2)

else不与while一起使用。你想要更像的东西:

void beginStorage(PicLib *lib)  
{  
    while (command != 'q') 
    { 
        //let's assume I add a whole bunch 
            //of stuff to PicLib and have some fun here 
    } 

    delete lib; 
    lib = NULL;  // Setting to NULL is not necessary in this case,
                 // you're changing a local variable that is about
                 // to go out of scope.
    cout << "Ciao" << endl;
}

delete看起来不错,但您应该确保记录beginStorage取得PicLib对象的所有权。这样,使用beginStorage的任何人都知道他们以后不必删除它。

答案 4 :(得分:2)

main.cpp中的删除是必要的。

这可能是个人偏好的问题,但我建议不要在单独的逻辑部分中调用new和delete(这里PicLib实例上的delete调用是在一个单独的函数中)。通常最好只分配一部分分配和解除分配的责任。

@AshleysBrain有一个更好的建议(关于创建堆栈的PicLib),尽管如果PicLib占用太多内存,这可能会导致问题。

答案 5 :(得分:1)

通常你想要在新的地方删除。它使会计更容易。更好的是使用智能指针(在这种情况下为scoped_ptr),这意味着即使while的主体抛出异常并提前终止,您的代码仍然是正确的。

答案 6 :(得分:0)

一切看起来都不错。

main.cpp中的删除是必要的,因为如果你没有调用delete,那么析构函数不会运行,你的数组也不会被删除。你也会泄漏类的内存,而不仅仅是数组。

答案 7 :(得分:0)

是的,否则将不会调用PicLib的析构函数。

虽然有一个风格说明:如果您在函数中新建了一个方法范围对象,请尝试在同一个函数中删除它。作为一名初级工程师,他不得不经历大型项目来修复其他人的内存泄漏......这使得其他人阅读起来容易得多。从它的外观来看,你可以在beginStorage()返回后删除* lib。然后在一个地方更容易看到* lib的范围。