在学习不同的语言时,我经常看到动态分配的对象,通常是Java和C#,如下所示:
functionCall(new className(initializers));
我知道这在内存管理语言中是完全合法的,但是这种技术可以在C++中使用而不会导致内存泄漏吗?
你的代码是有效的(假设functionCall()实际上保证指针被删除),但它很脆弱,并且会在大多数C++程序员的头脑中发出警报.
您的代码存在多个问题:
首先,谁拥有指针?谁负责解放它?调用代码无法执行此操作,因为您不存储指针.这意味着被调用的函数必须这样做,但对于那个查看该函数的人来说,这一点并不清楚.同样,如果我从其他地方调用代码,我当然不希望函数在传递给它的指针上调用delete!
如果我们使您的示例稍微复杂一些,它可能会泄漏内存,即使被调用的函数调用delete也是如此.说它看起来像这样:functionCall(new className(initializers), new className(initializers));
想象一下第一个成功分配,但第二个抛出一个异常(可能是内存不足,或者类构造函数引发异常).函数调用永远不会被调用,并且无法释放内存.
简单(但仍然很混乱)的解决方案是首先分配内存,然后存储指针,然后将其释放到声明的相同范围内(因此调用函数拥有内存):
className* p = new className(initializers); functionCall(p); delete p;
但这仍然是一团糟.如果functionCall抛出异常怎么办?那么p将不会被删除.除非我们在整个事情中添加一个try/catch,但是sheesh,那太乱了.如果函数变得有点复杂,并且可能在functionCall之后但在删除之前返回怎么办?哎呀,内存泄漏.无法维持.代码不好.
因此,一个很好的解决方案是使用智能指针:
boost::shared_ptrp = boost::shared_ptr (new className(initializers)); functionCall(p);
现在处理内存的所有权.该shared_ptr
公司拥有的记忆,并保证它会得到释放.std::auto_ptr
当然,我们可以使用它来 shared_ptr
实现您通常期望的语义.
请注意,我仍然在单独的行上分配内存,因为在进行函数调用的同一行上进行多次分配的问题仍然存在.其中一人可能仍然扔,然后你泄露了记忆.
智能指针通常是处理内存管理所需的绝对最小值.但很多时候,好的解决办法是写自己的RAII类.
className
应该在堆栈上分配,并在其构造函数中,进行new
必要的分配.在它的析构函数中,它应该释放那些记忆.这样,您可以保证不会发生内存泄漏,并且您可以使函数调用如此简单:
functionCall(className(initializers));
C++标准库的工作原理如下.std::vector
就是一个例子.你永远不会分配一个矢量new
.您在堆栈上分配它,并让它在内部处理它的内存分配.
是的,只要你释放函数内部的内存.但这绝不是C++的最佳实践.
这取决于.
这将内存的"所有权"传递给functionCAll().它需要释放对象或保存指针,以便以后可以释放它.传递像这样的原始指针的所有权是在代码中构建内存问题的最简单方法之一 - 泄漏或双重删除.