ostrstream将常量字符串解释为指针 [英] ostrstream interprets constant string as pointer
问题描述
在清理旧的C/C ++应用程序的调试宏时遇到了这个问题:我们有一个从ostrstream
继承的Tracer类(我知道自C ++ 98起就不推荐使用,但是此应用程序是用1998!),我们这样使用:
I ran across this problem while cleaning up the debug macros of an old C/C++ application: We have a Tracer class inheriting from ostrstream
(I know it's been deprecated since C++98, but this application was written in 1998!) which we use like this:
Tracer() << "some" << " message" << " here";
现在,如果链中的第一个值是如上所述的常量字符串,则在Tracer上调用ostrstream::str()
的结果(在析构函数中完成,将结果插入队列中)将包含指针的十六进制表示形式到此字符串而不是文本.因此,上面的语句将产生类似"0x401a37 message here"
的内容.对于旧的宏,这不会发生,因为它们的第一个值总是很长(线程ID),现在已被删除.
Now if the first value in the chain is a constant string like above, the result of calling ostrstream::str()
on the Tracer (which is done in the destructor, inserting the result into a queue) contains a hexadecimal representation of the pointer to this string instead of the text. Thus the above statement would yield something like "0x401a37 message here"
. This didn't occur with the old macros as they always had a long (Thread ID) as the first value which has now been removed.
使用gdb进入该目录显示,对于第一次插入,此操作在ostrstream上调用operator<<(void const*)
,而随后的插入调用operator<< <...>(basic_ostream<...>&, char const*)
(出于可读性考虑将其删除).
Stepping into it with gdb showed that for the first insertion, this calls operator<<(void const*)
on the ostrstream, while the subsequent insertions call operator<< <...>(basic_ostream<...>&, char const*)
(templating removed for readability).
有人可以解释这种行为吗?有什么干净的方法可以解决此问题?我发现了一个简单的解决方法,它使用<< left
作为第一个参数-这样安全吗?有更好的方法可以做到这一点吗?
Can somebody explain this behaviour? What would be a clean way to fix this? I have found an easy workaround, which is using << left
as the first argument - is this safe? Are there better ways to do this?
这是一个最小化的示例:
Here's a minimized example:
#include <strstream>
#include <iostream>
using namespace std;
class Trace : public ostrstream {
public:
Trace();
virtual ~Trace();
};
Trace::Trace() : ostrstream() {}
Trace::~Trace() {
static_cast< ostrstream& >(*this) <<ends;
char * text = ostrstream::str();
cout << "MESSAGE: "<< text <<endl;
delete[] text;
}
int main(){
Trace() << "some" << " text" << " here";
Trace() << left << "some" << " text" << " here";
Trace() << 123 << " text" << " here";
}
推荐答案
之所以如此工作,是因为Tracer()
是一个临时(右值),无法绑定到operator<<(basic_ostream<...>&,
中的非常量引用.
It works this way because the Tracer()
is a temporary (rvalue) that can not bind to the non-const reference in operator<<(basic_ostream<...>&,
.
但是,您可以调用像operator<<(void const*)
这样的成员函数,因为它不需要左值.
However, you can call member functions like operator<<(void const*)
, because that doesn't require an lvalue.
然后,成员函数返回对流对象的引用,可以在调用序列中的下一个operator<<
时使用 .
The member function then returns a reference to the stream object which can be used in calling the next operator<<
in the sequence.
以这种方式调用任何成员函数,例如Tracer() << left
或Tracer() << flush
,因此将引用转换"为左值引用是非常安全的.
Calling any member function this way, like Tracer() << left
or Tracer() << flush
, and thus "convert" the reference to an lvalue reference is quite safe.
如果碰巧具有C ++ 11兼容的编译器,则标准库甚至包含一个operator<<(basic_ostream<...>&&,
可以为您完成此操作.在那种情况下,您不再需要解决方法.
If you happen to have a C++11 compliant compiler, the standard library even contains an operator<<(basic_ostream<...>&&,
which does this for you. In that case you don't need the workaround anymore.
这篇关于ostrstream将常量字符串解释为指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!