1

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

主文件

...
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中的删除是否必要?这里的一切看起来都很棒吗?

4

8 回答 8

5

有几个问题:

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

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

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

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

在开始存储()

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

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

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

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

class PivLib
{
    private:
        std::vector<Pic>   databases;
};
于 2010-03-03T17:04:50.697 回答
3

是的,你用new创建的任何东西都 必须delete 删除,用new[]创建的任何东西都 必须delete[] 删除,在某些时候。

不过,我会在您的代码中指出一些事情:

  • 比使用 new[] 和 delete[] 更喜欢 std::vector<>。它会为你做内存管理。还可以查看 auto_ptr、shared_ptr 和 C++0x 中用于自动内存管理的 unique_ptr 等智能指针。这些有助于避免忘记删除并导致内存泄漏。如果可以,请不要使用 new/new[]/delete/delete[] !
  • 如果您必须新建和删除某些内容,那么在类构造函数中新建并在类析构函数中删除是一个非常好的主意。当抛出异常、对象超出范围等时,它们的析构函数会被自动调用,因此这有助于防止内存泄漏。它被称为 RAII。
  • beginStorage删除它的参数可能是个坏主意。如果你使用不是用new创建的指针调用函数,它可能会崩溃,因为你不能删除任何指针。如果main()在堆栈上创建一个 PicLib 而不是使用 new 和 delete,并且 beginStorage 获取引用而不删除任何内容,那会更好。
于 2010-03-03T17:02:03.043 回答
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
于 2010-03-03T16:57:40.787 回答
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知道他们以后不必删除它。

于 2010-03-03T16:58:55.927 回答
2

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

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

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

于 2010-03-03T17:04:55.507 回答
1

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

于 2010-03-03T17:04:33.063 回答
0

一切看起来都很好。

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

于 2010-03-03T16:58:52.343 回答
0

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

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

于 2010-03-03T17:06:21.400 回答