在下面的例子中
class X
{
int *r;
public:
X() {
cout << "X is created";
r = new int[10];
};
~X() {
cout<< "X is destroyed";
delete [] r;
};
};
class Y
{
public:
Y() {
X x;
throw 44;
};
~Y() {
cout << "Y is destroyed";
};
};
我从一个网站得到了RAII的这个例子并且有些怀疑。请帮忙。
答案 0 :(得分:9)
在X
的构造函数中,如果new
失败,则抛出异常(std::bad_alloc
)。这意味着构造函数永远不会完成,因此对象的生命周期永远不会启动,因此它的析构函数永远不会被调用(没有对象),并且new[]
和delete[]
之间不存在不匹配。 (X
应该有一个用户声明的拷贝构造函数和一个用户声明的拷贝赋值运算符作为实现,如果构造成功并且复制或分配了对象,则会破坏这种保证。)
在Y
中,如果它在其构造函数中分配内存并且此分配成功则需要确保如果构造的其余部分在任何时候抛出异常并且构造函数完成时释放此内存在析构函数中释放内存(假设内存设计为持续对象生命周期的长度)。
为了使这更容易,任何分配的内存应立即交给一个对象,其唯一的责任是释放内存。让一个类管理指向多个已分配内存块的原始指针是一个复杂且容易出错的管理代码的配方。
答案 1 :(得分:8)
你不必。如果失败,构造函数将抛出std::bad_alloc
。即:
new int[]
分配失败,抛出std::bad_alloc
。永远不会分配内存。因此没有泄漏。
这里对于Y的析构函数是安全的,因为y construcotr没有分配任何内存。如果我们还需要在y构造函数中做一些内存分配怎么办?
你仍然没有问题。分配失败将抛出std::bad_alloc
。失败是使用你班级的人的责任。
new int[]
分配成功。delete[]
是new int[]
。同样,这里没有泄露任何资源。
请注意,您确实需要警惕多次分配。即:
class Foo
{
int * r;
public:
Foo() {
r = new int;
throw myException;
};
~Foo() {
delete r;
};
};
现在我们有资源泄漏。当从构造函数抛出异常时,该对象永远不会完全构造。由于它从未完全构建,因此它永远不会被称为析构函数。因此我们泄漏r
。