stringstream临时ostream返回问题

时间:2009-10-08 22:20:14

标签: c++ iostream stringstream temporary

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

// #define LOG(x) // for release 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" << 3);

不起作用:

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

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

我认为这是因为&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;运算符比它来自的字符串流更长。

或者我错了?

(为什么string()以这种方式工作?是因为它返回对它自己的引用吗?我假设是的。)

我真的很想这样做,因为在登录发布模式时我会省去额外的分配。

任何以这种方式完成任务的指针或技巧都会受到欢迎。在我的实际解决方案中,我有许多不同的日志功能,它们都比这更复杂。所以我更希望在调用代码中以某种方式实现它。 (如果可能的话,不要修改我的#define)

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

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

匹配varargs类似printf的日志函数,它采用char *,string()和ostream()以及采用string(),exception()和HRESULT的非vararg函数。

2 个答案:

答案 0 :(得分:7)

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

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

虽然没有:

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

(它写一个十六进制数字,后跟“1”数字)

解释的一些要素:

  • rvalue不能绑定到非const引用
  • 可以在临时
  • 上调用成员函数
  • std :: ostream有一个成员运算符&lt;&lt;(void *)
  • std :: ostream有一个成员运算符&lt;&lt;(int)
  • 对于char *,运算符不是成员,它是运算符&lt;&lt;(std :: ostream&amp;,const char *)

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

在第一个示例中,一切正常,因为首先调用成员运算符&lt;&lt;(int),然后返回的引用可以传递给运算符&lt;&lt;(ostream&amp;,const char *)

在第二个例子中,运算符&lt;&lt;(不能用“std :: stringstream()”作为第一个参数调用,因为这将要求它绑定到非const引用。但是,成员运算符&lt ;&lt;(void *)没问题,因为它是会员。

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

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

答案 1 :(得分:6)

LOG()宏更改为:

#define LOG(x) do { std::stringstream s; s << x; log(s.str()); } while(0)

这将允许您在调试日志中使用以下语法,因此您不必手动构造字符串流。

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

然后将其定义为无需发布,您将无需额外分配。