C++的流设计很糟糕

C++的流设计很糟糕

最近需要提供一个功能,采用类似C++流输出的格式输出一些日志信息, 例如Log(FATAL) << "log to" .

我找了两个类似项目来研究,google的 glog 和 log4cpp, 它们都支持以C++流输出格式进行输出.

但是研究到最后,我发现最大的问题是, 如果按照C++的流输出格式进行输出, 将无法判定需要输出的信息到哪里是结束.比如log << "hello " << "world",是无法判断到底在输出"hello"还是"world"的时候上面的参数输入已经结束了.上面两个项目中, 解决这个问题的办法大致是相同的,以下面可编译运行代码为例说明它们的做法(在linux g++下面编译通过):
#include  < iostream >
#include 
< sstream >

#ifdef __DEPRECATED
//  Make GCC quiet.
 # undef __DEPRECATED
 # include 
< strstream >
 # define __DEPRECATED
#else
 # include 
< strstream >
#endif

using   namespace  std;

class  LoggerStream :  public  std::ostrstream {
 
public :
  LoggerStream(
char   *  buf,  int  len)
   : ostrstream(buf, len),
    buf_(buf),
    len_(len) {
  }

  
~ LoggerStream() {
    
//  do the real fucking output
    cout  <<  buf_;
  }

 
private :
  
char   * buf_;
  
int  len_;
};

int  main() {
  
char  buf[ 100 =  { ' \0 ' };

  LoggerStream(buf, 
sizeof (buf))  <<   1   <<   "  hello world\n " ;

  cout 
<<   " buf =  "   <<  buf  <<  endl;

  
return   0 ;
}

在上面的代码中, 开始进行输出的时候首先初始化一个LoggerStream对象, 而在输出参数输入完毕的时候将调用它的析构函数,在这个析构函数中才完成真正的输出动作.也就是说,由于对输入参数结束位置判断手段的缺失,C++中不得不采用这个手段在析构函数中完成最终的输出工作.
这样的做法,最大的问题是,频繁的构造/析构开销大,而且每个"<<"操作符背后又需要调用ostream的operator<<,也就是假如你的输入参数有三个将调用operator <<三次(当然是经过重载的,不一定都是同一个operator<<),因此,假如需要考虑多线程的话,那么一次输入有多个函数函数中被调用,仍然是问题.天,要使用这门语言写出正确的程序来,需要了解底下多少的细节呢?!

最后,我向项目组反映这个问题,一致同意以C中类似sprintf可变参数的形式实现这个功能.可变参数解决这个问题,就我的感觉而言,就是输入参数的时候,稍显复杂,需要用户指定输入的格式.然而,其实这个做法也有好处:作为函数的使用者,你必须明确的知道你在做什么并且反馈给你所使用的函数.明确的,无歧义的使用函数,而不是依靠所谓函数重载猜你的用意,我想也是避免问题的一个手段.gcc中, 提供了对可变参数检查的机制,见 这里.

你可能感兴趣的:(C++的流设计很糟糕)