在构造对象时,我在异常的情况下发现了一些有趣的行为:
class bookentry
{
public:
bookentry(){
t1.reset(new test1); //0
test1 *t11 = new test1; //1
test2 *t22 = new test2; //2
throw 1; //3
}
protected:
private:
auto_ptr<test1> t1;
auto_ptr<test2> t2;
};
从我的测试:
如果我们从 test2的构造函数(#2) 中抛出异常,那么
如果我们从 bookentry的构造函数(#3)中抛出一个异常,这一次,事情会变得不同: t22 永远不会被破坏(既不会调用t22的析构函数)或释放记忆),t11与上述相同
我只是对#2
的句子感到困惑test2 * t22 = new test2; // 2
似乎当我们从类构造函数抛出异常时,新表达式将确保调用相应的delete,但通过新表达式完全创建的任何对象在该异常泄露之前(t11,如果我们在#3处抛出异常,则为t11和t22)。
所以,如果我们编写如下代码并且第5个对象构造失败:
test2 * t2s = new test2 [10];
然后,它似乎更安全了一点:
我的问题是,这是标准的c ++行为吗?我只是测试msvc 2012和gcc 4.4.6,两者都看起来实现了这样的机制。
修改 更清楚地提出我的问题:
在某些情况下,您需要在其他正常函数中编写类似t1.reset(new test1)[在我的代码中参见#1]的代码。在这种情况下,如果从构造函数抛出异常。我如何推断程序状态?有内存泄漏吗?
我的测试确保在这种情况下这些没有内存泄漏,但这是标准的c ++行为吗?
答案 0 :(得分:3)
规则很简单:
在该范围内完全创建的所有对象都将被销毁
上述规则不适用于指向动态存储上分配的对象的原始指针(分配有new
)。他们需要明确delete
d。使用new
时,您明确拥有资源管理,调用delete
来释放资源是您的工作,编译器不会为您执行此操作。
好读:
<强> Constructor failures - Herb Sutter 强>
请注意,在C ++中管理资源的最佳方法是使用RAII和智能指针。在构造函数中更是如此。不使用任何原始指针,只需将它们包装在智能指针中,并且在出现此类异常时,它们将自动为您的对象执行资源管理。在代码示例中使用auto_ptr
而不是原始指针时,您刚刚体验过这种能力。