stringstream临时ostream返回问题 [英] stringstream temporary ostream return problem

查看:116
本文介绍了stringstream临时ostream返回问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个包含以下部分的记录器:

  // #define LOG mode 
#define LOG(x)log(x)

log(const string& str);
log(const ostream& str);

有以下想法:

  LOG(Test); 
LOG(string(Testing)+123);
stringstream s;
LOG(s <<Testing<< 1<<two<< 3);

这一切都按预期工作,但当我这样做:

  LOG(stringstream()<Testing<< 1<<two< 

不起作用:

  void log(const ostream& os)
{
std :: streambuf * buf = os.rdbuf();
if(buf&& typeid(* buf)== typeid(std :: stringbuf))
{
const std :: string& format = dynamic_cast< std :: stringbuf&>(* buf).str();
cout<<格式<< endl;
}
}

会导致'format'包含垃圾数据,而不是通常的正确字符串。



我认为这是因为临时ostream返回的<



(为什么string()工作这是因为它返回一个引用本身?我假设是。)



我真的想这样做,因为我会消除登录发布模式时的额外分配。



欢迎任何指示或技巧,以这种方式完成。在我的实际解决方案中,我有许多不同的日志函数,他们都比这更复杂。所以我宁愿在调用代码中以某种方式实现。 (而不是通过修改我的#define如果可能)



只是为了给出一个想法,我的一个实际#defines的例子:



#define LOG_DEBUG_MSG(format,...)\
LogMessage(DEBUG_TYPE,const char * filepos,sizeof(__QUOTE __(@__VA_ARGS__) \
格式,__VA_ARGS__)

它匹配varargs printf样日志函数, ,string()和ostream()以及带有string(),exception()和HRESULT的非vararg函数。

解决方案

>我认为我看到发生了什么。这产生预期的输出:

  log(std :: stringstream()<< 1< ); 

,但这不会:

  log(std :: stringstream()<<hello<< 

(它写入十六进制数字,后跟1数字)



一些元素的解释:




  • 一个右值不能绑定到一个非const引用

  • 可以在临时
  • 上调用成员函数
  • std :: ostream有一个成员运算符<<(void *)

  • std :: ostream有一个成员运算符<<(int)

  • 对于char *,运算符不是成员,它是运算符<< :: ostream& const char *)



在上面的代码中,std :: stringstream()创建一个临时。它的生命周期是没有问题的,因为它必须持续到它被声明的整个完整的表达式(即,直到调用log()返回)。



例如,一切工作正常,因为首先调用成员运算符<(int),然后返回的引用可以传递给运算符<<(ostream& const char *)



在第二个例子中,操作符<<(不能用std :: stringstream()作为第一个参数来调用,因为这将要求它绑定到一个非const引用。



顺便说一句:为什么不把log()函数定义为:

  void log(const std :: ostream& os)
{
std :: cout< .rdbuf()<< std :: endl;
}


I'm creating a logger with the following sections:

// #define LOG(x) // for release mode
#define LOG(x) log(x)

log(const string& str);
log(const ostream& str);

With the idea to do:

LOG("Test");
LOG(string("Testing") + " 123");
stringstream s;
LOG(s << "Testing" << 1 << "two" << 3);

This all works as intended, but when I do:

LOG(stringstream() << "Testing" << 1 << "two" << 3);

It does not work:

void log(const ostream& os)
{
  std::streambuf* buf = os.rdbuf();
  if( buf && typeid(*buf) == typeid(std::stringbuf) )
  {
    const std::string& format = dynamic_cast<std::stringbuf&>(*buf).str();
    cout << format << endl;
  }
}

results in 'format' containing junk data instead of the usual correct string.

I think this is because the temporary ostream returned by the << operator outlives the stringstream it comes from.

Or am I wrong?

(Why does string() work in this way? Is it because it returns a reference to itself? I'm assuming yes.)

I would really like to do it this way as I would be eliminating an additional allocation when logging in release mode.

Any pointers or tricks to get it done this way would be welcomed. In my actual solution I have many different log functions and they are all more complex than this. So I would prefer to have this implemented somehow in the calling code. (And not by modifying my #define if possible)

Just to give an idea, an example of one of my actual #defines:

#define LOG_DEBUG_MSG(format, ...) \
  LogMessage(DEBUG_TYPE, const char* filepos, sizeof( __QUOTE__( @__VA_ARGS__ )), \
  format, __VA_ARGS__)

which matches varargs printf-like log functions taking char*, string() and ostream() as well as non-vararg functions taking string(), exception() and HRESULT.

解决方案

I think I see what's happening. This produces the expected output:

log(std::stringstream() << 1 << "hello");

while this does not:

log(std::stringstream() << "hello" << 1);

(it writes a hex number, followed by the "1" digit)

A few elements for the explanation:

  • An rvalue cannot be bound to a non-const reference
  • It is OK to invoke member functions on a temporary
  • std::ostream has a member operator<<(void*)
  • std::ostream has a member operator<<(int)
  • For char* the operator is not a member, it is operator<<(std::ostream&, const char*)

In the code above, std::stringstream() creates a temporary (an rvalue). Its lifetime is not problematic, as it must last for the whole full expression it is declared into (i.e, until the call to log() returns).

In the first example, everything works ok because the member operator<<(int) is first called, and then the reference returned can be passed to operator<<(ostream&, const char*)

In the second example, operator<<(cannot be called with "std::stringstream()" as a 1st argument, as this would require it to be bound to a non-const reference. However, the member operator<<(void*) is ok, as it is a member.

By the way: Why not define the log() function as:

void log(const std::ostream& os)
{
    std::cout << os.rdbuf() << std::endl;
}

这篇关于stringstream临时ostream返回问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆