下面的代码会导致C ++中的内存泄漏吗

时间:2020-03-06 14:51:40  来源:igfitidea点击:
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 ...不必清理整数...

温迪