stringstream临时ostream返回问题

Mar*_*ius 6 c++ iostream temporary stringstream

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

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

log(const string& str);
log(const ostream& str);
Run Code Online (Sandbox Code Playgroud)

有了这样的想法:

LOG("Test");
LOG(string("Testing") + " 123");
stringstream s;
LOG(s << "Testing" << 1 << "two" << 3);
Run Code Online (Sandbox Code Playgroud)

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

LOG(stringstream() << "Testing" << 1 << "two" << 3);
Run Code Online (Sandbox Code Playgroud)

这是行不通的:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

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

我认为这是因为<<运算符返回的临时ostream比它来自的字符串流更长.

还是我错了?

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

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

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

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

#define LOG_DEBUG_MSG(format, ...) \
  LogMessage(DEBUG_TYPE, const char* filepos, sizeof( __QUOTE__( @__VA_ARGS__ )), \
  format, __VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

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

Éri*_*ant 7

我知道发生了什么.这会产生预期的输出:

log(std::stringstream() << 1 << "hello");
Run Code Online (Sandbox Code Playgroud)

虽然这不是:

log(std::stringstream() << "hello" << 1);
Run Code Online (Sandbox Code Playgroud)

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

解释的几个要素:

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

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

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

在第二个例子中,operator <<(不能用"std :: stringstream()"作为第一个参数调用,因为这需要将它绑定到非const引用.但是,成员运算符<<(void*)没关系,因为它是会员.

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

void log(const std::ostream& os)
{
    std::cout << os.rdbuf() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*kin 6

改变你的LOG()宏:

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

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

LOG("Testing" << 1 << "two" << 3);
Run Code Online (Sandbox Code Playgroud)

然后将它定义为什么都没有发布,你将没有额外的分配.

  • @KayEss:do/while是这样的,分号可以添加到行的末尾,这使得对`LOG()`的调用看起来更自然.见http://stackoverflow.com/questions/154136/ (2认同)