ACE 过程中记录的一些笔记

以下是滇狐学习 ACE 过程中记录的一些笔记, 随着学习过程的深入, 这部分内容会逐渐增加。

1 ACE 的 Singleton

对于初学者来说, Singleton 模式应该是最容易理解和应用的设计模式之一了。 毫不掩饰地说, Singleton 模式也是滇狐最讨厌的设计模式之一。 虽然不容否认, 它是一个非常有用的设计模式, 但在现实生活中, 绝大部分情况下, 该设计模式被滥用了, 构建出一些模块间耦合度很高, 可扩展性极差的程序。 这里滇狐不打算详细讨论 Singleton 模式, 只想谈谈在 ACE 里使用 Singleton 的一些注意事项。

1.1 不要让静态对象依赖 Singleton 对象

静态对象是万恶之源, 最大的罪恶是初始化顺序无法预料, 静态对象之间出现互相依赖时, 非常容易发生种种莫名其妙的故障。 ACE_Singleton 很好地解决了这个问题, 它在一个对象第一次被使用的时候创建, 这样当一个对象在构造期间依赖另一个对象的时候, 通过这个机制就能保证被依赖的对象完整构造后, 依赖者才继续往下执行。

然而, ACE_Singleton 引用的对象在构造的时候, 需要依赖 Object_Manager 对象。 如果我们选择不使用静态Object_Manager 的话, Object_Manager 需要在我们显示调用 ACE::init() 之后才能正常使用; 而就算我们使用了静态的 Object_Manager, 它的构造时期也是不可预料的, 因此, 永远不要在静态对象里引用 ACE_Singleton

1.2 Singleton 在析构过程中不要相互引用

当我们调用 ACE::fini() 的时候, 所有登记并被构造的 ACE_Singleton 引用的对象就被析构了。 虽然ACE_Singleton 完美地解决了互相依赖的对象之间的构造顺序的问题, 但对于析构顺序, 我们仍然是不可知的。 如果我们在一个 Singleton 的析构过程中引用了另外一个 Singleton, 而被引用的 Singleton 却又不幸地被提前析构了, 那你的程序就等着 Crash 吧。

说到这里, 滇狐忍不住又要感叹一句, Singleton 模式大大增加了模块之间的耦合度, 降低了模块的灵活性, 实在不是一个很好的设计模式。

1.3 多调用一次 ACE::init() 和 ACE::fini() 又何妨

虽然在有的平台下, ACE 会自动将 main 函数重定义, 并主动替你把 ACE::init() 和 ACE::fini() 调用好, 但这一行为不能保证在所有平台下都正常运作。 ACE::init() 和 ACE::fini() 里面都有嵌套层次计数机制, 因此只要它们能够保证成对出现, 并且不出现交叉嵌套, 多调用一遍并不会出现任何问题, 我们不妨在 main 函数的开头和结尾分别再调用一次 ACE::init() 和 ACE::fini()

2 为 WinMain 编写的 parse_command_line

ACE 提供了 GNU getopt 的一个包装 ACE_Get_Opt, 用来解析命令行是非常方便的。 可惜无论是 getopt 还是ACE_Get_Opt, 都要求提供 int argc, char *argv[] 形式的命令行参数, 对于使用 WinMain 的程序而言, 这多少有些不便。 因此滇狐编写了这个命令行解析函数

3 将日志输入重定向到 Output Window

在 Windows 下使用 ACE, 对于非控制台程序而言, 由于没有 stderr 输出可以查看, 在调试的时候, 无论是把日志输出到文件, 或是输出到系统事件查看器, 使用起来都不是那么方便。 其实, 利用 ACE 强大的日志重定向功能, 把日志输出到调试器的 Output Window (或者叫 Trace Window) 是非常容易的。

首先, 我们定义一个 Callback 类, 用于拦截 ACE 日志设施的输出:

#include  <ace/Log_Msg_Callback.h>
#include  <ace/Log_Record.h>

class Callback :  public ACE_Log_Msg_Callback
{
public:
     void setVerbose( unsigned  long verbose);
     void log(ACE_Log_Record &log_record);

private:
     unsigned  long _verbose;
};

void Callback::setVerbose( unsigned  long verbose)
{
    _verbose = verbose;
}

void Callback::log(ACE_Log_Record &log_record)
{
     char buffer[ACE_Log_Record::MAXVERBOSELOGMSGLEN];
    log_record.format_msg(ACE_TEXT( ""), _verbose, buffer);
    OutputDebugString(buffer);
}

然后将日志重定向到 Callback 对象的实例即可:

#include  <ace/Log_Msg.h>

...

    Callback callback;
    ACE_LOG_MSG->msg_callback(&callback);
    ACE_LOG_MSG->set_flags(ACE_Log_Msg::MSG_CALLBACK);

...

    ACE_LOG_MSG->clr_flags(ACE_Log_Msg::MSG_CALLBACK);

警告! 在程序退出之前, 务必将指向 Callbak 的日志设施关闭, 否则当 callback 对象析构之后, 如果还有别的日志需要输出的话, 这个无效的指针将会导致你的程序整个崩溃掉。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值