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();
}
如何在上面的代码? 如何能在构造函数抛出后可避免内存泄漏?
是的,这将导致内存泄漏。 当构造函数抛出,没有析构函数将被调用(在这种情况下,你不表明释放动态分配的对象的析构函数,但是让我们假设你有一个)。
这是使用智能指针的一个重要原因 - 因为智能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();
声明):
当异常是一个构造函数中抛出还有,你应该采取的妥善处理,可能在对象的中止施工已经发生资源分配方面注意到几件事情:
- 被构造为对象的析构函数将不被调用。
- 对于包含在对象的类成员对象的析构函数会被调用
- 这是被构造为对象的存储器将被释放。
这意味着,如果你的对象拥有的资源,有可供清理可能在构造函数抛出已经获得这些资源的2种方法:
- 捕获异常,释放资源,然后重新抛出。 这可能是很难得到正确的,可以成为一个维护问题。
- 使用对象来管理资源寿命(RAII),并使用这些对象的成员。 当你的对象构造函数抛出异常,成员对象将有desctructors打来电话,将不得不释放其寿命他们是负责该资源的机会。
这两款新的会被泄露。
堆上创建对象的地址赋给一个名为智能指针,使其在智能指针析构函数时得到的异常被抛出调用内删除- ( 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分配,而不是在其他情况下,自动释放只适用。 此外,被释放的内存是那些为对象分配的成员,而不是你可能已经分配的任何内存在构造函数中说。 也就是说,它会释放()的成员变量的内存 , 品脱 ,objsomeclass和psomeclass,而不是从全新SomeClass的分配的内存和新的INT()。
我相信,最多的回答是错误的,仍然会出现内存泄漏。 如果构造函数抛出异常(因为它从来没有完成初始化,也许有些成员也从未达到它们的构造函数调用)的类成员的析构函数不会被调用。 析构函数类的析构函数调用时只被调用。 那才有意义。
这个简单的程序演示了。
#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。
如果您在构造函数中抛出,你应该清理传来呼叫抛出之前的一切。 如果您使用的继承或析构函数抛出,你真的不应该。 该行为是奇数(没有我的标准很方便,但它可能是不确定的?)。
是的,该代码将导致内存泄漏。 内存模块中使用的“新”时,将引发异常没有释放分配。 这是背后的动机的一部分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;
}
你的一切“新”需要删除,否则会导致内存泄漏。 所以,这两条线:
psomeclass = new someclass();
pint = new int();
会造成内存泄露,因为你需要做的:
delete pint;
delete psomeclass;
在finally块,以避免它们被泄露。
此外,该行:
base temp = base();
是不必要的。 你只需要做到:
base temp;
添加“=碱()”是不必要的。
您需要删除psomeclass ...它没有必要清理整...
RWendi