我有一个带有静态成员的类:
class MyClass
{
public:
static const SomeOtherClass myVariable;
};
我在CPP文件中初始化如下:
const SomeOtherClass MyClass::myVariable(SomeFunction());
问题是,SomeFunction()
从注册表中读取值。如果该注册表项不存在,则会引发异常。这会导致我的程序爆炸而不给用户任何有用的输出...是否有某些方法可以捕获异常以便我可以记录它?
答案 0 :(得分:7)
我不太喜欢static
数据成员,初始化问题最重要。
每当我必须进行重要处理时,我会欺骗并使用本地static
代替:
class MyClass
{
public:
static const SomeOtherClass& myVariable();
};
const SomeOtherClass& MyClass::myVariable()
{
static const SomeOtherClass MyVariable(someOtherFunction());
return MyVariable;
}
这样,异常只会在第一次使用时抛出,但对象将是const
。
这是延迟执行的非常强大的习惯用语。它有一点开销(基本上编译器每次进入方法时都会检查一个标志),但最好先担心正确性;)
如果从多个线程调用它:
boost::once
库Boost.Threads
const
,你可能不在乎它是否多次初始化,除非someOtherFunction
不支持并行执行(小心资源) 指南:仅对简单对象(不能抛出)使用static
或global
变量实例化,否则使用local static
变量来延迟执行,直到可以抓住产生的例外情况。
答案 1 :(得分:5)
也许最好的办法是将注册表项添加到列表而不是查找它,然后只要输入main(),就可以查看列表中的所有键。我不想说教,但是这样的情况正是为什么在进入main()之前进行重要处理通常是个坏主意。
答案 2 :(得分:5)
当然 - 将SomeFunction()
包裹在如下函数中:
int static_error;
void SomeFunctionWrapper() {
try {
SomeFunction();
}
catch(...) { // something more specific if possible
static_error = 1;
}
}
然后在进入main时,您需要检查static_error != 0
并在需要时打印相应的错误消息(遗憾的是,您无法知道异常处理程序中是否存在std::cerr
,所以如果你想从那里打印,你将不得不做类似C FILE *的输出。
答案 3 :(得分:0)
您可以将该函数包装在另一个捕获异常的函数中,并向用户发出问题警告(或创建具有安全默认值的密钥)
答案 4 :(得分:0)
您可以创建一个延迟对象构造的包装类。然后当它第一次使用时,如果构造函数抛出,它将抛出它首次使用的位置。
这样做的好处是在调用main()之前没有运行很多代码,如果你实际上没有使用全局对象,它将永远不会被初始化。
代码:
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/thread/once.hpp>
#include <iostream>
const boost::once_flag DEFAULT_ONCE_FLAG = BOOST_ONCE_INIT;
template <typename T>
class DelayedConstruction {
public:
DelayedConstruction(boost::function<T* (void) > const & init = &DelayedConstruction::default_initializer ) :
m_initializer(init), m_flag(DEFAULT_ONCE_FLAG) { }
T const & operator*() const {
boost::call_once(m_flag, boost::bind(&DelayedConstruction::initialize, this) ) ;
if ( ! m_object )
throw std::runtime_error("Object could not be initialized") ;
return *m_object ;
}
T const * operator->() const {
boost::call_once(m_flag, boost::bind(&DelayedConstruction::initialize, this) ) ;
if ( ! m_object )
throw std::runtime_error("Object could not be initialized") ;
return m_object.get() ;
}
static T* default_initializer() { return new T; }
private:
void initialize() const {
m_object.reset( m_initializer() ) ;
}
boost::function<T* (void) > m_initializer ;
mutable boost::scoped_ptr<T> m_object ;
mutable boost::once_flag m_flag ;
};
struct Foo {
Foo(int x = 0) : m_x(x) {
if ( x == 1 ) throw std::runtime_error("Can't be 1") ;
}
int m_x ;
} ;
Foo* make_custom_foo() {
return new Foo(1) ;
}
DelayedConstruction< const Foo > g_myFoo ;
DelayedConstruction< const Foo > g_anotherFoo(&::make_custom_foo) ;
int main() {
try {
std::cout << "My Foo: " << g_myFoo->m_x << std::endl ;
std::cout << "Another Foo: " << g_anotherFoo->m_x << std::endl ;
} catch ( std::runtime_error const & e ) {
std::cout << "ERROR: " << e.what() << std::endl ;
}
return 0 ;
}
打印出来:
My Foo: 0
ERROR: Can't be 1