我有下面的代码片段,这是为了演示构造函数的function-try-block的用例。因为Controller
的构造函数没有抛出它成功创建的对象,即当抛出异常时,client_
成员变量也应该不再存在,是这样吗?如果是这样,那么调用deinit()
来清理client_
是安全的吗?如果不安全,假设client_
是一个原始指针,那么我如何捕获异常并为它做清理工作?
class Client {
public:
Client() { std::cout << "Client()" << std::endl; }
~Client() { std::cout << "~Client()" << std::endl; }
void Start() { throw "Start() failed with exception"; }
};
class Controller {
private:
std::shared_ptr<Client> client_;
public:
Controller() try {
client_ = std::make_shared<Client>();
client_->Start();
} catch (...) {
deinit();
}
~Controller() {
deinit();
}
private:
void deinit() {
if (client_) {
client_.reset();
}
}
};
1条答案
按热度按时间soat7uwm1#
当抛出异常时,client_ member变量也不应该存在,对吗?
不,这是不正确的。异常在新类示例的
client_
成员被构造之后被抛出。一个类的构造函数只有在新类示例的所有成员都被构造之后才被调用;构造函数的工作是在所有的类成员都构造好之后,完成任何构造类本身的任务。
一旦你进入构造函数,你就可以保证新类示例的所有成员都被完全构造,你可以把它带到银行。
调用deinit()安全吗
当然,它是“安全的”,因为它是定义的行为。但是,在这种情况下,它是完全不必要的。如果在构造函数中抛出异常,则新类示例的所有构造成员都将以相反的构造顺序被自动销毁。
client_
将被正常销毁,就像类完全构造然后在稍后的某个时候被销毁一样。如果client_是一个原始指针,那么我如何捕获异常并对其进行清理?
与上面的代码差不多,但它不是一个原始指针,而是一个
shared_ptr
,它处理这个问题。