热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

POCOC++库学习和分析异常、错误处理、调试

POCOC库学习和分析--异常、错误处理、调试1.异常处理C同C语言相比,提供了异常机制。通过使用try,catch关键字可以捕获异常,这种机制使得程序
POCO C++库学习和分析 -- 异常、错误处理、调试


1. 异常处理

        C++同C语言相比,提供了异常机制。通过使用try,catch关键字可以捕获异常,这种机制使得程序员在程序异常发生时,可以通过判断异常类型,来决定程序是否继续执行,并在程序结束之前优雅的释放各类资源。当然对于C++的异常机制也存在着很多的争议。在这里,并不对此展开讨论,只介绍一下Poco中的异常类。


        Poco中的异常类:
        1. 所有的异常类都是Poco::Exception的子类。
        2. Poco::Exception继承自std::exception类。
        3. Foundation库中涉及的异常类,包括了下面一些:
                   a) Poco::LogicException类负责处理程序错误,包括了:
                           AssertionViolationException
                          NullPointerException
                           NullValueException
                           BugcheckException
                           InvalidArgumentException
                           NotImplementedException
                           RangeException
                           IllegalStateException
                           InvalidAccessException
                           SignalException
                           UnhandledException
                   b) Poco::ApplicationException类负责处理应用程序相关的错误,即使用Poco库的用户自定义异常。
                   c) Poco::RuntimeException类负责处理程序运行时的错误,包括了:
                           RuntimeException
                           NotFoundException
                           ExistsException
                           TimeoutException
                           SystemException
                           RegularExpressionException
                           LibraryLoadException
                           LibraryAlreadyLoadedException
                           NoThreadAvailableException
                           PropertyNotSupportedException
                           PoolOverflowException
                           NoPermissionException
                           OutOfMemoryException
                           DataException
                           DataFormatException
                           SyntaxException
                           CircularReferenceException
                           PathSyntaxException
                           IOException
                           ProtocolException
                           FileException
                           FileExistsException
                           FileNotFoundException
                           PathNotFoundException
                           FileReadOnlyException
                           FileAccessDeniedException
                           CreateFileException
                           OpenFileException
                           WriteFileException
                           ReadFileException
                           UnknownURISchemeException


        成员函数及数据定义:
        1. Poco::Exception包括了一个名字,这是一个静态的字符串,用来描述异常本身。比如说LogicException名字为"Logic exception",TimeoutException名字为"Timeout"。
        2. Poco::Exception还包含了一个字符串消息,这是用来进一步描述异常的。使用的的人可以在运行时定义它。比如都是LogicException异常,函数一处抛出异常时可定义为"Function1",函数二处抛出时异常时可定义为用"Function2",它可以用来说明异常发生的具体位置和原因。
        3. 一个可选的嵌套异常类
        4. 构造函数:
                   a) 可以使用0个,1个或2个字符串参数来构造异常。在Poco::Exception内部存储的时候,第二个字符串会使用字符":"和第一个字符串串联。
                   b) 构造时如果使用了字符串和嵌套异常的方式,嵌套异常会被复制一份。
        5. Poco::Exception支持拷贝和赋值运算符
        6. const char* name()
                   返回异常的名称
        7. const std::string& message()
                   返回在构造时传入的消息字符串
        8. std::string displayText() const
                   同时返回异常名字和消息字符串,中间使用": "分隔
        9. const Exception* nested() const
                   如果存在嵌套异常的话,返回之歌指向嵌套异常的指针,否则返回0
        10. Exception* clone() const
                   返回一个异常的拷贝
        11. 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)

// MyException.cpp
#include "MyException.h"POCO_IMPLEMENT_EXCEPTION(MyException, Poco::Exception,"Something really bad happened...")


        宏展开分别为:

// 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...";
}
...


        下面是一个例子:

#include "Poco/Exception.h"
#include
int main(int argc, char** argv)
{Poco::Exception* pExc &#61; 0;try{throw Poco::ApplicationException("just testing");}catch (Poco::Exception& exc){pExc &#61; exc.clone();}try{pExc->rethrow();}catch (Poco::Exception& exc){std::cerr <}

2. 断言

        POCO库中提供了一些断言的宏来进行运行时检查&#xff0c;这些断言能够提供出错代码的行号和文件信息。
        1. Debugger::_assert(cond)
         如果cond ≠ true时&#xff0c;抛出一个AssertionViolationException异常。
        2. poco_assert_dbg(cond)
           同poco_assert类似&#xff0c;但是只在debug模式下起作用
        3. poco_check_ptr(ptr)
           如果ptr为空&#xff0c;则抛出NullPointerException异常
        4. poco_bugcheck(), poco_bugcheck_msg(string)
           抛出BugcheckException异常

        POCO的断言类在debug调试模式下(比如在Visual C&#43;&#43;)中时&#xff0c;会触发一个breakpoint。比如&#xff1a;

void foo(Bar* pBar)
{poco_check_ptr (pBar);...
}
void baz(int i)
{poco_assert (i >&#61; 1 && i <3);switch (i){case 1:...break;case 2:...break;default:poco_bugcheck_msg("i has invalid value");}
}

        这主要是因为Poco中的断言类是通过Poco::Debugger去实现的&#xff0c;在Poco::Debugger底层调用了不同操作系统的API&#xff0c;去判断程序是否处于调试状态。如VC下,调用了

BOOL WINAPI IsDebuggerPresent(VOID);
VOID WINAPI DebugBreak(VOID);

3. NDC(Nested Diagnostic Context)

3.1  概述

        NestedDiagnosticContext是为了多线程诊断而设计的。我们在写程序时&#xff0c;一般都需要同时处理多个线程。为了更加便捷的处理多线程情况&#xff0c;为每个线程产生各自的日志。Neil Harrison 在他的书中"Patterns for Logging Diagnostic Messages," in Pattern Languages of Program Design 3, edited by R. Martin, D. Riehle, and F. Buschmann (Addison-Wesley, 1997) 中提出了一个方法。独特地标记每个日志请求&#xff0c;用户把上下文信息送入NDC&#xff0c;NDC是 Nested Diagnostic Context的缩写。在这本书里提到了3种日志方法&#xff0c;分别是&#xff1a;
        1. DiagnosticLogger
         分离日志和程序其他模块
        2. TransactionalBuckets
        事务桶&#xff0c;为事务单独建立日志
        3. TypedDiagnostics
        类型化诊断&#xff0c;为所有的诊断信息提供统一的展现


我们还是回到Poco中的NDC上。在Poco中和NDC相关的内容包括了&#xff0c;NestedDiagnosticContext类&#xff0c;NDCScope类&#xff0c;宏poco_ndc和poco_ndc_dbg。其中NestedDiagnosticContext类维护一个NDC对象&#xff0c;其中包括了上下文的栈信息&#xff0c;有函数方法名&#xff0c;源文件代码文件名&#xff0c;行号。宏poco_ndc(func) or poco_ndc_dbg(func)申明了一个NDCScope对象。而NDCScope对象则完成了上下文的入栈工作。下面是一个例子&#xff1a;

#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;
}


3.2 实现

3.2.1 线程本地存储

        在Poco中实现时&#xff0c;用了一些小技巧&#xff0c;即线程本地存储。我们来看Poco中TLS的类图&#xff1a;



        CurrentThreadHolder类是TLS实现的具体类&#xff0c;在每个Thread对象中包含了一个CurrentThreadHolder对象。Thread创建的时候&#xff0c;CurrentThreadHolder会调用不同操作系统的API函数&#xff0c;获取并保存一个固定槽位&#xff0c;用于保存Thread对象的指针。
        每个Thread对象中还包含了一个ThreadLocalStorage对象。ThreadLocalStorage类用于保存具体的线程信息数据&#xff0c;它是一个TLSSlot对象的集合。通过泛型实现TLSSlot后&#xff0c;ThreadLocalStorage可用于保存任何数据的。

        使用了TLS技术后&#xff0c;调用Thread的静态函数current可以获取到每个线程对象Thread的指针&#xff0c;然后再通过这个Thread对象的指针&#xff0c;可以获取到ThreadLocalStorage对象&#xff0c;并最终获取或保存数据于TLSSlot中。

        通过类的静态函数获取类实例的指针&#xff0c;在C&#43;&#43;中是不存在的&#xff0c;这需要操作系统支持&#xff0c;只有Thread对象才能做到这一点。



3.2.2 NDC

        在来看一张Poco中NDC类的类图&#xff1a;





        使用者通过调用宏poco_ndc和poco_ndc_dbg&#xff0c;来构建一个NDCScope对象。宏定义如下&#xff1a;

#define poco_ndc(func) \Poco::NDCScope _theNdcScope(#func, __LINE__, __FILE__)#if defined(_DEBUG)#define poco_ndc_dbg(func) \Poco::NDCScope _theNdcScope(#func, __LINE__, __FILE__)
#else#define poco_ndc_dbg(func)
#endif


        NDCScope实现了诊断信息上下文的入栈出栈工作&#xff0c;它通过调用NestedDiagnosticContext类的静态函数current实现了此功能。其定义如下&#xff1a;

inline NDCScope::NDCScope(const std::string& info)
{NestedDiagnosticContext::current().push(info);
}inline NDCScope::NDCScope(const std::string& info, int line, const char* filename)
{NestedDiagnosticContext::current().push(info, line, filename);
}inline NDCScope::~NDCScope()
{NestedDiagnosticContext::current().pop();
}

        NestedDiagnosticContext类的current()是个静态函数&#xff0c;其定义如下&#xff1a;

namespace
{static ThreadLocal ndc;
}NestedDiagnosticContext& NestedDiagnosticContext::current()
{return ndc.get();
}


        而ThreadLocal是一个辅助类&#xff0c;用于获取线程对象的本地存储信息或者是主线程的本地存储信息。

template
class ThreadLocal/// This template is used to declare type safe thread/// local variables. It can basically be used like/// a smart pointer class with the special feature/// that it references a different object/// in every thread. The underlying object will/// be created when it is referenced for the first/// time./// See the NestedDiagnosticContext class for an/// example how to use this template./// Every thread only has access to its own/// thread local data. There is no way for a thread/// to access another thread&#39;s local data.
{typedef TLSSlot Slot;public:ThreadLocal(){}~ThreadLocal(){}C* operator -> (){return &get();}C& operator * ()/// "Dereferences" the smart pointer and returns a reference/// to the underlying data object. The reference can be used/// to modify the object.{return get();}C& get()/// Returns a reference to the underlying data object./// The reference can be used to modify the object.{TLSAbstractSlot*& p &#61; ThreadLocalStorage::current().get(this);if (!p) p &#61; new Slot;return static_cast(p)->value();}private:ThreadLocal(const ThreadLocal&);ThreadLocal& operator &#61; (const ThreadLocal&);
};

        到这里Poco中所有的NDC流程都被打通了&#xff0c;用户终于可以实现按线程打印日志信息了。


&#xff08;版权所有&#xff0c;转载时请注明作者和出处  http://blog.csdn.net/arau_sh/article/details/8698353&#xff09;




转:https://www.cnblogs.com/napu/archive/2013/04/08/5375887.html



推荐阅读
  • 巧用arguments在Javascript的函数中有个名为arguments的类数组对象。它看起来是那么的诡异而且名不经传,但众多的Javascript库都使用着它强大的功能。所 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了[从头学数学]中第101节关于比例的相关问题的研究和修炼过程。主要内容包括[机器小伟]和[工程师阿伟]一起研究比例的相关问题,并给出了一个求比例的函数scale的实现。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了机器学习手册中关于日期和时区操作的重要性以及其在实际应用中的作用。文章以一个故事为背景,描述了学童们面对老先生的教导时的反应,以及上官如在这个过程中的表现。同时,文章也提到了顾慎为对上官如的恨意以及他们之间的矛盾源于早年的结局。最后,文章强调了日期和时区操作在机器学习中的重要性,并指出了其在实际应用中的作用和意义。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • React基础篇一 - JSX语法扩展与使用
    本文介绍了React基础篇一中的JSX语法扩展与使用。JSX是一种JavaScript的语法扩展,用于描述React中的用户界面。文章详细介绍了在JSX中使用表达式的方法,并给出了一个示例代码。最后,提到了JSX在编译后会被转化为普通的JavaScript对象。 ... [详细]
  • 本文是一篇翻译文章,介绍了async/await的用法和特点。async关键字被放置在函数前面,意味着该函数总是返回一个promise。文章还提到了可以显式返回一个promise的方法。该特性使得async/await更易于理解和使用。本文还提到了一些可能的错误,并希望读者能够指正。 ... [详细]
  • 动量|收益率_基于MT策略的实战分析
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了基于MT策略的实战分析相关的知识,希望对你有一定的参考价值。基于MT策略的实战分析 ... [详细]
  • Postgresql备份和恢复的方法及命令行操作步骤
    本文介绍了使用Postgresql进行备份和恢复的方法及命令行操作步骤。通过使用pg_dump命令进行备份,pg_restore命令进行恢复,并设置-h localhost选项,可以完成数据的备份和恢复操作。此外,本文还提供了参考链接以获取更多详细信息。 ... [详细]
  • 前段时间做一个项目,需求是对每个视频添加预览图,这个问题最终选择方案是:用canvas.toDataYRL();来做转换获取视频的一个截图,添加到页面中,达到自动添加预览图的目的。 ... [详细]
  • 基于分布式锁的防止重复请求解决方案
    一、前言关于重复请求,指的是我们服务端接收到很短的时间内的多个相同内容的重复请求。而这样的重复请求如果是幂等的(每次请求的结果都相同,如查 ... [详细]
author-avatar
廖汉林1026_843
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有