为什么写入临时字符串流对象只打印对象地址
Why does writing into temporary string stream object only print object addresses?
以下代码片段是我使用的记录器的简化版本。它扩展std::ostringstream
,可以使用<<
运算符填充。销毁后,所有内容将写入std::cout
。
Logger()
,将(<<
)直接写入临时对象,我希望它打印该输入,但是,它只打印std::cout
上的某物地址。写入临时对象的引用时,Logger().stream()
按预期工作。
为什么会这样?
顺便说一句,这种行为只发生在我必须使用的 C++98-land (ideone) 中。使用 C++11(coliru)和 C++14(ideone),两个调用变体都按预期工作。C++11/14 有什么不同?
#include <iostream>
#include <sstream>
class Logger : public std::ostringstream
{
public:
~Logger()
{
std::cout << this->str() << std::endl;
}
Logger& stream()
{
return *this;
}
};
int main( int argc, char ** argv )
{
// 1.
// Prints an address, e.g. 0x106e89d5c.
Logger() << "foo";
// 2.
// Works as expected.
Logger().stream() << "foo";
// What is the difference between 1. and 2.?
return 0;
}
处理const char *
插入的operator<<
是非成员模板:
template< class Traits >
basic_ostream<char,Traits>& operator<<(basic_ostream<char,Traits>& os, const char* s);
它通过非常量(左值)引用获取其流,该引用不绑定到临时引用。
在 C++98/03 中,最可行的函数是成员operator<<(const void *)
,它打印一个地址。
在 C++11 及更高版本中,库为右值流提供了特殊operator<<
:
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
它执行os << value
并返回os
,本质上是在左值流上执行输出操作。
相关事实:
-
Logger()
是右值,但Logger().stream()
是右值。 -
获取指针并打印其地址的
operator<<
是ostream&
的成员,而获取const char*
并打印字符串的operator<<
是一个自由函数,template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const char* s);
请注意,第一个参数是非常量左值引用,因此它不能绑定到右值。因此,如果流是右值,则此重载不可行。因此,const char*
将转换为const void*
并打印其地址。使用 Logger().stream()
(左值)时,此重载获胜并打印字符串。
在 C++11 中,添加了一个新的右值流插入运算符:
template <class charT, class traits, class T>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&& os, const T& x);
效果os << x
.现在这个重载在Logger() << "foo"
中获胜,并转发参数,就好像流是一个左值一样。然后调用之前给出的 free 函数。
C++11 添加了重载的non-member operator<<
:
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
现在,您认为在Logger()
情况下要呼叫的接线员是以下接线员:
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
const char* s );
这适用于Logger().stream()
情况,因为这是一个左值引用,但这不适用于Logger() << "foo"
情况。 Logger()
不能绑定到左值引用。在那里,唯一可行的重载是成员operator<<
:
basic_ostream& operator<<( const void* value );
打印地址。
- 如何仅使用对象名称打印特定于对象的成员
- 如何使用gdb制作一个可以漂亮地打印每个对象的C++函数
- 打印抽象对象 c++
- 为什么平均打印数组元素比打印单个对象慢C++?
- 打印指向的对象
- 如何在 c++ 中打印存档中的对象向量
- 如何获取列表的每个对象并调用getName方法来打印其名称
- 我重载了 << 和 = 运算符。为什么当我将一个对象分配给另一个对象并尝试打印它时,我会被打印出来?
- 将对象放入地图后打印对象
- 打印对象的映射,其中另一个对象作为键
- 如何在运行时在对象数组中动态追加新对象C++并打印它们
- 如何在C++中打印对象向量的内容
- 打印出对象向量中的每个元素C++
- 对象数组打印空白字符串
- C++ - 打印派生类对象的矢量<base*> 元素
- C++ - 使用 std::list,如何打印对象的私有成员的链接列表?
- 未正确的校验和释放对象 - 打印时错误
- GDB:如何从子对象打印/调用父函数
- 从对象打印二维矢量时出错
- 从对象打印2D int向量