看了会glog使用文档,很快就被下面的语法形式吸引了,这颗语法糖,真是太完美了。
1 LOG(INFO) << "Found " << num_cookies << " cookies";
2 CHECK(fp->Write(x) == 4) << "Write failed!";
3
符号“<<”,第一眼就能理解,使用了流对象重载操作符“<<”的方法。
问题是,如果LOG(INFO)实际上是一个流对象的话,那它怎么做到“在禁止输出日志时不编译“<<”右边的代码”呢?
要知道LOG4cpplus,可以是用了下面的语法结构才实现的,依靠最后那个括号。glog的语法显然更胜一筹了。
1LOG(INFO,"Found" << num_cookies << " cookies");
于是,跟踪代码,总于一窥真面目,大为感叹。翻译成原始代码,应该这样的,
1LogMessage().stream() << "Found " << num_cookies << " cookies";
巧妙之处,就在于LogMessage是一个类,LogMessage()生成了一个临时局部对象,它的生命期仅在这一行代码范围内。
就是说,这行结束的时候,LogMessage就被析构,在析构函数中,去执行真正的日志输出。
写上面例子,是为了引出本文真正的主题,利用C++对象的生命期来实现特殊代码控制流程。
早年,学习Basic语言的时候,听老师说了结构化编程中流程控制的三大元素“顺序、选择、循环”,真以为有了三大元素,便无所不能了,其他的都是多余的。
但实际上,一个例外便是:在一个作用域开始时,执行一些代码;在作用域退出时,执行另一些代码。比如,Win32上的句柄管理,获取了句柄,最后一定要释放。
我个人认为,这种流程控制,在现代C++编程中是如此重要,为其提供专门语法机制毫不为过。
然而,C++前辈们用一种可说巧妙,也可卑劣的方式,来处理这个问题,即利用对象在作用域中的构造与析构。
说它卑劣,是因为如此重要的特性,在C++教材里是找不到,使它得不到应有的重视。
当然不管怎么说,这个特性是C++优于C的极少特例之一。
总结一下,我们可以在四种对象作用范围内,实现上述的特殊流程控制:
1. 全局对象生命期。一般不推荐使用全局变量,没有多少实际意义;
2. 类成员变量,即类生命期。最典型的就是智能指针了。
3.局部变量,即函数中的块作用域。这是最普遍的,比如什么互斥量守护,资源句柄守护等等。
4.局部匿名变量(不知道是否该这样命名),在代码行的作用域。这很少见,glog算是见到的第一个了。