下面的代码会导致C ++中的内存泄漏吗
class someclass {}; class base { int a; int *pint; someclass objsomeclass; someclass* psomeclass; public: base() { objsomeclass = someclass(); psomeclass = new someclass(); pint = new int(); throw "constructor failed"; a = 43; } } int main() { base temp(); }
在上面的代码中,构造函数将引发。哪些对象将被泄漏,以及如何避免内存泄漏?
int main() { base *temp = new base(); }
上面的代码怎么样?构造函数引发后如何避免内存泄漏?
解决方案
我们"所有"的所有内容都需要删除,否则会导致内存泄漏。所以这两行:
psomeclass = new someclass(); pint = new int();
将导致内存泄漏,因为我们需要执行以下操作:
delete pint; delete psomeclass;
在finally块中,以避免它们被泄漏。
另外,这一行:
base temp = base();
是没有必要的。我们只需要执行以下操作:
base temp;
不需要添加" = base()"。
是的,该代码将泄漏内存。引发异常时,不会释放使用" new"分配的内存块。这是RAII背后动机的一部分。
为避免内存泄漏,请尝试以下操作:
psomeclass = NULL; pint = NULL; /* So on for any pointers you allocate */ try { objsomeclass = someclass(); psomeclass = new someclass(); pint = new int(); throw "constructor failed"; a = 43; } catch (...) { delete psomeclass; delete pint; throw; }
如果抛出了构造函数,则应清除调用throw之前的所有内容。如果我们使用继承或者抛出析构函数,则实际上不应该这样做。行为很奇怪(没有我的标准方便,但可能未定义?)。
这两个新的将被泄漏。
将创建的堆对象的地址分配给已命名的智能指针,以便在引发异常(RAII)时会被调用的智能指针析构函数中将其删除。
class base { int a; boost::shared_ptr<int> pint; someclass objsomeclass; boost::shared_ptr<someclass> psomeclass; base() : objsomeclass( someclass() ), boost::shared_ptr<someclass> psomeclass( new someclass() ), boost::shared_ptr<int> pint( new int() ) { throw "constructor failed"; a = 43; } };
现在,当在构造函数中引发异常时,当堆栈展开时,将调用psomeclass和pint析构函数,并且这些析构函数将取消分配已分配的内存。
int main(){ base *temp = new base(); }
对于使用(non-plcaement)new的普通内存分配,如果构造函数抛出异常,则将自动释放由new运算符分配的内存。就为什么要麻烦释放单个成员(响应对Mike B的回答的评论)而言,自动释放仅在新分配的对象的构造函数中引发异常时才适用,而在其他情况下则不适用。另外,释放的内存是为对象成员分配的内存,而不是构造函数内部可能分配的任何内存。即它将释放成员变量a,pint,objsomeclass和psomeclass的内存,但不会释放从new someclass()和new int()分配的内存。
是的,它将泄漏内存。当构造函数抛出异常时,不会调用任何析构函数(在这种情况下,我们不会显示释放动态分配对象的析构函数,而是假设我们拥有一个析构函数)。
这是使用智能指针的主要原因,因为智能Poitner是成熟的对象,它们将在异常的堆栈展开期间被调用析构函数,并有机会释放内存。
如果使用诸如Boost的scoped_ptr <>模板之类的类,则类可能看起来更像:
class base{ int a; scoped_ptr<int> pint; someclass objsomeclass; scoped_ptr<someclass> psomeclass; base() : pint( new int), objsomeclass( someclass()), psomeclass( new someclass()) { throw "constructor failed"; a = 43; } }
这样就不会有内存泄漏(默认的dtor也会清理动态内存分配)。
总结一下(希望这也能回答有关
base* temp = new base();
陈述):
在构造函数中引发异常时,在正确处理对象的异常中止构造中可能发生的资源分配方面,应注意以下几点:
- 不会调用正在构造的对象的析构函数。
- 该对象的类中包含的成员对象的析构函数将被调用
- 将释放正在构造的对象的内存。
这意味着,如果对象拥有资源,则有两种方法可用于清除构造函数抛出时可能已获取的那些资源:
- 捕获异常,释放资源,然后重新抛出。这可能很难正确纠正,并且可能成为维护问题。
- 使用对象来管理资源生存期(RAII),并将这些对象用作成员。当对象的构造函数引发异常时,成员对象将具有调用的描述符,并将有机会释放其负责生命周期的资源。
我们需要删除psomeclass ...不必清理整数...
温迪