内容概要:
POCO异常类;定义自己的异常;抛出和捕捉异常;调试工具
一、POCO异常类
所有的POCO异常都从Poco::Exception类继承,
需要包含头文件 #include "Poco/Exception.h"
Poco::Exception类是从std::exception类继承的。
一些Poco::Exception的子类:
Poco::LogicException (程序逻辑错误)
Poco::RuntimeException (运行时错误)
Poco::ApplicationException (应用特定异常)
完整列表可以查阅参考手册。
一个Poco::Exception包括以下部分:
一个名字(一个简短字符串,用于描述异常主要情况)
一段信息(描述引起异常的原因)
嵌套异常其他(可选的)
通过传递1个、2个字符串参数或空参数来构建(采用“第一个参数:第二个参数”的形式在内部存储)。
如果通过一个字符串和一个嵌套异常做参数进行构建,那么嵌套异常将被复制。
支持拷贝构造。
const char* name() const
返回异常名字
const std::string& message() const
返回异常信息文本
std::string displayText() const
返回“名字:信息”字符串
const Exception* nested() const
返回嵌套异常的指针,如果没有则返回空。
Exception* clone() const
返回当前异常的一个拷贝。
void rethrow() const
重新抛出异常。
二、定义自己的异常
定义Poco::Exception的子类是很无聊的,必须重载很多的虚函数,因此可以用宏
减轻单调重复的劳动。
POCO_DECLARE_EXCEPTION 用来声明异常类。
POCO_IMPLEMENT_EXCEPTION 用来实现异常类
// MyException.h
#include "Poco/Exception.h"
POCO_DECLARE_EXCEPTION(MyLib_API, MyException, Poco::Exception)
class MyLib_API MyException: public Poco::Exception
{
public:
MyException();
MyException(const std::string& msg);
MyException(const std::string& msg, const std::string& arg);
MyException(const std::string& msg, const Poco::Exception& nested);
MyException(const MyException& exc);
~MyException();
MyException& operator = (const MyException& exc);
const char* name() const;
...
};
// MyException.cpp
#include "MyException.h"
POCO_IMPLEMENT_EXCEPTION(MyException, Poco::Exception,
"Something really bad happened...")
...
const char* MyException::name() const throw()
{
return "Something really bad happened...";
}
...
三、抛出和捕捉异常
根据C++的传统,总是通过数值抛出异常,通过引用捕捉异常。
使用displayText()显示异常。可以把一个异常暂存起来,稍后再抛出。
#include "Poco/Exception.h"
#include
int main(int argc, char** argv)
{
Poco::Exception* pExc = 0;
try
{
throw Poco::ApplicationException("just testing");
}
catch (Poco::Exception& exc)
{
pExc = exc.clone();
}
try
{
pExc->rethrow();
}
catch (Poco::Exception& exc)
{
std::cerr << exc.displayText() << std::endl;
}
delete pExc;
return 0;
}
四、断言
POCO有很多用于运行时检查的宏:
poco_assert(cond)
抛出一个AssertionViolationException 如果cond ≠ true。
poco_assert_dbg(cond)
类似于poco_assert,但是仅仅用于在调试时。
poco_check_ptr(ptr)
抛出NullPointerException异常 如果 ptr 为空
poco_bugcheck(), poco_bugcheck_msg(string)
抛出BugcheckException
poco_assert, poco_assert_dbg, poco_check_ptr和
poco_bugcheck 将当前文件名称和行号也加入到异常文本中。
在调试状态,抛出异常会触发一个断点。
void foo(Bar* pBar)
{
poco_check_ptr (pBar);
}
...
void baz(int i)
{
poco_assert (i >= 1 && i < 3);
}
switch (i)
{
case 1:
...
break;
case 2:
...
break;
default:
poco_bugcheck_msg("i has invalid value");
}
五、嵌套诊断上下文(NestedDiagnosticContext)
根据Neil Harrison在PLOP3的文章"Patterns for Logging Diagnostic Messages"。
一个 NDC 保存了一个上下文信息栈,包括:
1、一个信息字符串(方法名称)
2、源代码文件名称和行号。
NDCs 对于用上下文信息(栈追踪)标示日志信息非常有用。
每个线程有自己的NDC.
#include "Poco/NestedDiagnosticContext.h"
NDCScope类关注的是把一个上下文放入相应的栈,或者从栈里弹出。
poco_ndc(func) 或者 poco_ndc_dbg(func)声明了一个NDCScope (poco_ndc_dbg 仅用于debug模式)
用NDC::dump()输出栈追踪信息
注意: NestedDiagnosticContext是NDC的typedef。
#include "Poco/NestedDiagnosticContext.h"
#include
void f1()
{
poco_ndc(f1);
Poco::NDC::current().dump(std::cout);
}
void f2()
{
poco_ndc(f2);
f1();
}
int main(int argc, char** argv)
{
f2();
return 0;
}
六、调试版构建和发行版构建(Debug and Release Builds)
POCO支持独立的调试版和发行版,在调试版中,执行一些附加的运行时检查,
提供了一些额外的调试特性。这些也可以运用到自己的程序代码中。
对于调试构建,必须定义_DEBUG宏。poco_debugger()和
poco_debugger_msg(message)可以强制进入断点。
注意poco_assert, poco_check_ptr和 poco_bugcheck 在debug和release时都可以用。
在调试状态,断点在抛出异常之前触发。
poco_assert_dbg和poco_debugger仅在调试状态有用。
七、调试器接口
Poco::Debugger类提供了调试器接口。
#include "Poco/Debugger.h"
用bool Debugger::isAvailable()检查是否运行在调试状态。
在Unix系统中要支持调试器,就要设置环境变量POCO_ENABLE_DEBUGGER.
用void Debugger::enter() 进入断点,用void Debugger::message()把信息写入调试器日志或标准输出。