我有一个需求,在C'tor中需要读取输入文件,但有时该文件不存在。
这个对象通常是静态持有的,因此在加载dll时会调用它的C'tor。
如果文件不存在,我无法捕获抛出的异常,因为这太早了,我的可执行文件会以不好看的方式崩溃。
我知道从C'tor中抛出异常是不好的做法,但如果文件不存在,我必须这样做。
是否有一种方法可以在加载dll时捕获异常?如果没有,是否有更好的解决方案呢?
谢谢, Gal
谢谢, Gal
我假设这个静态对象具有文件作用域(它在任何函数/类定义之外)。您可以考虑将其移动到访问器函数中,并仅通过该函数进行访问,就像这样:
class Object;
Object& getObject()
{
static Object object;
return object;
}
当第一次调用getObject()方法时,Object的静态实例将被初始化。如果Object的构造函数抛出异常,您可以轻松捕获异常。只需记住将每个getObject()调用包装在try/catch块中(否则异常会向上冒泡),这可能有点不方便,但另一方面,如果您知道程序逻辑流程中的逻辑“第一个”调用是哪个,您可以决定仅包装该调用。
在构造函数中抛出异常并不一定是一种不好的实践。事实上,RAII通常需要您这样做,因为对象具有必须满足的内部不变量,如果构造函数无法初始化对象并使其处于有效状态,则这是唯一的方法。
另一方面,在析构函数中抛出异常是一种不好的实践(也是一种危险的实践)。但是,在构造函数中抛出异常应该是可以接受的。
如果您可以使用c++11,则可以使用lambda和unique_ptr<>
解决此问题:
// In some_file.hpp
#pragma once
#include <memory>
#include <stdexcept>
class CtorThrows {
public:
CtorThrows (int value) {
if (value < 10) {
throw std::runtime_error("oops!");
}
}
};
class ClassWithStatic {
public:
private:
static std::unique_ptr<CtorThrows> bad_member_; // <-- static member
};
然后
// In some_file.cpp
#include "some_file.hpp"
// Create a lambda function to initialize the static member variable.
std::unique_ptr<CtorThrows> ClassWithStatic::bad_member_ = []() {
try {
int value = 5; // in this case, it is a bad value
// This only returns successfully if bad_value DOESN'T cause
// the ctor to throw and exception.
return std::make_unique<CtorThrows>(value);
} catch (std::runtime_error &e) {
std::cerr << "OOPs! Here's a nice error message" << std::endl;
exit(1);
}
return std::unique_ptr<CtorThrows>(nullptr);
}();
unique_ptr
可以让你即使在类具有删除或私有复制构造函数和复制赋值运算符的情况下也能实现这一点。你说得对,你无法捕获在静态对象初始化期间发生的异常。
由于你正在编写一个DLL:每个DLL都可以有一个入口点,在这个入口点内部,异常处理起作用。(这与主程序中的main函数相同)。我建议删除你的类的静态实例,用指针替换它们,并在dllmain中初始化这些指针。
这将彻底解决你的问题。
顺便说一下 - DLL入口点会在加载、卸载和其他事件(如进程附加/分离等)时被调用。请确保使用正确的位置来初始化你的类。