我正在尝试使我的C++代码异常安全,并遇到了一个问题,询问朋友或搜索网络都无济于事。
根据我的理解,当使用构造函数创建对象时可能会引发异常,创建代码需要用try
块括起来,异常处理是在catch(){}
中完成的。
如果创建是基于堆的(例如 new
使用默认分配器),我可以像这样将异常处理代码放在创建附近:
void f() {
// work unrelated to Hoge object here
try {
Hoge *pHoge = new Hoge(); // could throw an exception
} catch(HogeException& ex) {
// handle exception
}
// rest of work here
}
但是,如果创建是基于堆栈的,由于块的范围,我找不到这样做的方法并求助于下面的代码try
:
void g() {
// work unrelated to Hoge object here
try {
Hoge hoge; // could throw an exception
// rest of work here
} catch(HogeException& ex) {
// handle exception
}
}
如果上面的// rest of work
代码很大,对象创建和异常处理之间的位置距离可能会很长,从而降低代码的可读性......
我更喜欢异常处理代码靠近对象创建(也许这是try
- catch
结构的概念之一)。有什么解决办法吗?
// rest of work
委托给帮助程序函数,并将Hoge&
传递给该函数:
void RestOfWork(Hoge& hoge)
{
// rest of work here
}
void g() {
// work unrelated to Hoge object here
try {
Hoge hoge;
RestOfWork(hoge);
// rest of work here
} catch(HogeException& ex) {
// handle exception
}
}
顺便说一句,Hoge hoge();
并没有做你认为它做的事情。 您可能认为您正在声明一个名为 hoge
的类型为 Hoge
的对象,并通过调用默认构造函数对其进行初始化。 您实际上正在做的是声明一个名为 hoge
的函数,该函数不带任何参数并返回Hoge
by-value。 我已经在上面的代码中修复了这个问题。
编辑 事实上,正如@LightnessRacesInOrbit所建议的,Hoge
对象的构造也可以在延迟函数中进行,例如:
void RestOfWork()
{
Hoge hoge;
// rest of work here
}
void g() {
// work unrelated to Hoge object here
try {
RestOfWork();
} catch(HogeException& ex) {
// handle exception
}
}
执行此操作的合理方法是使用可为空的单项容器,例如 boost::optional
:
void g() {
// work unrelated to Hoge object here
boost::optional<Hoge> opt_hoge;
try {
opt_hoge = boost::in_place<Hoge>();
} catch(HogeException& ex) {
// handle exception
}
Hoge &hoge = *opt_hoge;
// rest of work here
}
如果您不能使用 Boost,std::unique_ptr
将以堆分配为代价:
void g() {
// work unrelated to Hoge object here
std::unique_ptr<Hoge> opt_hoge;
try {
opt_hoge = std::unique_ptr<Hoge>(new Hoge);
} catch(HogeException& ex) {
// handle exception
}
Hoge &hoge = *opt_hoge;
// rest of work here
}