将在C下面的代码原因内存泄漏++(Will the below code cause memory

2019-07-19 13:55发布

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();
}

如何在上面的代码? 如何能在构造函数抛出后可避免内存泄漏?

Answer 1:

是的,这将导致内存泄漏。 当构造函数抛出,没有析构函数将被调用(在这种情况下,你不表明释放动态分配的对象的析构函数,但是让我们假设你有一个)。

这是使用智能指针的一个重要原因 - 因为智能poitners是完全成熟的对象,他们将得到的析构函数的异常的堆栈展开期间调用,并有以释放内存的机会。

如果你使用类似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;
    }
}

而你也没有内存泄漏(和默认的析构函数也将清理动态内存分配)。


归纳起来(希望这也回答了关于这个问题

base* temp = new base();

声明):

当异常是一个构造函数中抛出还有,你应该采取的妥善处理,可能在对象的中止施工已经发生资源分配方面注意到几件事情:

  1. 被构造为对象的析构函数将被调用。
  2. 对于包含在对象的类成员对象的析构函数会被调用
  3. 这是被构造为对象的存储器将被释放。

这意味着,如果你的对象拥有的资源,有可供清理可能在构造函数抛出已经获得这些资源的2种方法:

  1. 捕获异常,释放资源,然后重新抛出。 这可能是很难得到正确的,可以成为一个维护问题。
  2. 使用对象来管理资源寿命(RAII),并使用这些对象的成员。 当你的对象构造函数抛出异常,成员对象将有desctructors打来电话,将不得不释放其寿命他们是负责该资源的机会。


Answer 2:

这两款新的会被泄露。

堆上创建对象的地址赋给一个名为智能指针,使其在智能指针析构函数时得到的异常被抛出调用内删除- ( 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& 品脱析构函数将被调用时,当异常在构造函数中抛出的堆栈放松,而那些析构函数会回收分配的内存。

int main(){
    base *temp = new base();
}

对于使用由运营商新的,如果构造函数抛出异常时自动释放分配(非plcaement)新的普通内存的内存分配。 在何苦释放个别成员(在响应评论迈克B的回答)说,当一个例外对象的构造函数抛出被new'ly分配,而不是在其他情况下,自动释放只适用。 此外,被释放的内存是那些为对象分配的成员,而不是你可能已经分配的任何内存在构造函数中说。 也就是说,它会释放()的成员变量的内存品脱 ,objsomeclasspsomeclass,而不是从全新SomeClass的分配的内存和新的INT()。



Answer 3:

我相信,最多的回答是错误的,仍然会出现内存泄漏。 如果构造函数抛出异常(因为它从来没有完成初始化,也许有些成员也从未达到它们的构造函数调用)的类成员的析构函数不会被调用。 析构函数类的析构函数调用时只被调用。 那才有意义。

这个简单的程序演示了。

#include <stdio.h>


class A
{
    int x;

public:
    A(int x) : x(x) { printf("A constructor [%d]\n", x); }
    ~A() { printf("A destructor [%d]\n", x); }
};


class B
{
    A a1;
    A a2;

public:
    B()
    :   a1(3),
        a2(5)
    {
        printf("B constructor\n");
        throw "failed";
    }
    ~B() { printf("B destructor\n"); }
};


int main()
{
    B b;

    return 0;
}

用下面的输出(使用克++ 4.5.2):

A constructor [3]
A constructor [5]
B constructor
terminate called after throwing an instance of 'char const*'
Aborted

如果你的构造失败,中途那是你的责任来对付它。 更糟的是,异常可能从你的基类的构造函数抛出! 处理这些案件的方式是通过使用“功能try块”(但即使如此,你必须仔细编写你的部分初始化的对象的破坏)。

那么正确的做法,您的问题将是这样的:

#include <stdio.h>


class A
{
    int x;

public:
    A(int x) : x(x) { printf("A constructor [%d]\n", x); }
    ~A() { printf("A destructor [%d]\n", x); }
};


class B
{
    A * a1;
    A * a2;

public:
    B()
    try  // <--- Notice this change
    :   a1(NULL),
        a2(NULL)
    {
        printf("B constructor\n");
        a1 = new A(3);
        throw "fail";
        a2 = new A(5);
    }
    catch ( ... ) {   // <--- Notice this change
        printf("B Cleanup\n");
        delete a2;  // It's ok if it's NULL.
        delete a1;  // It's ok if it's NULL.
    }

    ~B() { printf("B destructor\n"); }
};


int main()
{
    B b;

    return 0;
}

如果你运行它,你会得到预期的输出,其中仅分配的对象被破坏,释放。

B constructor
A constructor [3]
B Cleanup
A destructor [3]
terminate called after throwing an instance of 'char const*'
Aborted

您仍然可以智能共享指针做出来,如果你想与更多的复制。 写一个类似的构造函数:

class C
{
    std::shared_ptr<someclass> a1;
    std::shared_ptr<someclass> a2;

public:
    C()
    {
        std::shared_ptr<someclass> new_a1(new someclass());
        std::shared_ptr<someclass> new_a2(new someclass());

        // You will reach here only if both allocations succeeded. Exception will free them both since they were allocated as automatic variables on the stack.
        a1 = new_a1;
        a2 = new_a2;
    }
}

祝你好运,Tzvi。



Answer 4:

如果您在构造函数中抛出,你应该清理传来呼叫抛出之前的一切。 如果您使用的继承或析构函数抛出,你真的不应该。 该行为是奇数(没有我的标准很方便,但它可能是不确定的?)。



Answer 5:

是的,该代码将导致内存泄漏。 内存模块中使用的“新”时,将引发异常没有释放分配。 这是背后的动机的一部分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;
 }



Answer 6:

你的一切“新”需要删除,否则会导致内存泄漏。 所以,这两条线:

psomeclass = new someclass();
pint = new int(); 

会造成内存泄露,因为你需要做的:

delete pint;
delete psomeclass;

在finally块,以避免它们被泄露。

此外,该行:

base temp = base();

是不必要的。 你只需要做到:

base temp;

添加“=碱()”是不必要的。



Answer 7:

您需要删除psomeclass ...它没有必要清理整...

RWendi



文章来源: Will the below code cause memory leak in c++