如果我在构造函数中使用不同的指针(不在同一个数组中)分配了多个动态资源,那么在没有使用智能指针的情况下,如果它们中的任何一个在构造函数中失败,那么清理它的方法是什么?
我使用下面的代码来处理两个资源案例,但如果以后需要更多资源,它就无法扩展。
任何想法都很受欢迎。
例如,
class Foo {
private:
int *p;
bool is_p_alloc;
int *q;
bool is_q_alloc;
public:
Foo()
try
:p(NULL), q(NULL), is_p_alloc(false), is_q_alloc(false)
{
p = new int;
is_p_alloc = true;
q = new int;
is_q_alloc = true;
}
catch(...)
{
if(is_p_alloc)
{
delete p;
p = NULL;
}
if(is_q_alloc)
{
delete q;
q = NULL;
}
throw bad_alloc();
}
};
答案 0 :(得分:3)
使用单一责任和专用类:
#include <memory>
class Foo
{
std::unique_ptr<int> p;
std::unique_ptr<int> q;
public:
Foo() : p(std::make_unique<int>()), q(std::make_unique<int>()) {}
Foo(Foo &&) = default;
Foo & operator=(Foo &&) = default;
};
请记住:每当您发现自己在撰写new
,delete
或析构函数时,您都无法正确理解您的图书馆。
答案 1 :(得分:1)
所有关于异常处理,堆栈展开和本地保留的资源。 我对您的代码进行了一些更改,并添加了一些注释来表示问题和解决方案。
class Foo {
private:
int *p;
bool is_p_alloc;
int *q;
bool is_q_alloc;
public:
Foo() : p(NULL), q(NULL), is_p_alloc(false), is_q_alloc(false)
{
try{
p = new int; // The operator new may throw an exception. If it throws an exception, then following
// expressions it this block won't be executed, so you don't have to worry about them.
is_p_alloc = true;
q = new int; // The operator new may throw an exception, but if the previous new operator had already
//thrown an exception, then it was not executed anyway.
is_q_alloc = true;
}
catch(...) // Good technique!
{
if(is_p_alloc)
{
delete p; // Yes, you should delete p, because if new operator in the statement "q = new int;"
// throw an exception, then the actual object of Foo is not totally constructed, thus
// the destructor of this new object of Foo can not be executed, thus the memory which
// is pointed by p won't be deleted from heap.
p = NULL;
}
if(is_q_alloc) // If one of the new operators in the try-block throws an exception, then the the
// statement "is_q_alloc = TRUE;" is not executed, so the value of is_q_alloc is false.
// is_q_alloc will never be true in this context, and you don't have to delete the
// memory pointed by q because if this memory reserved in the heap, then the object of Foo is totally constructed.
{
delete q;
q = NULL;
}
throw; // Good technique!
}
}
};