在C ++中将字符串打印到临时流对象

时间:2011-11-04 18:10:52

标签: c++ object reference const temporary

我有一种特殊类型的ostringstream,我试图将文本作为临时对象输出,但我遇到了一些麻烦。要清楚,这基本上就是我想做的事情:

ostringstream() << "PARTY DOWN!" << endl;

现在在你说:“但是Zack,那个代码完全没用!在线的最后,对象被破坏了,你怎么知道它是否做了什么?”,听我说。我不会尝试使用普通的ostringstreams,而是尝试使用析构函数实际提供数据退出对象的路径的派生类。所以实际上,它看起来更像是这样:

specialstringstream() << "PARTY DOWN!" << endl;

其中specialstringstream有一个析构函数,可以将文本转储到别处。

我不会详细说明为什么要这样做。你必须相信我对我需要做的事情有意义,它很适合现有的巨大代码库。

这就是问题所在:当我这样做时,所有内容都会编译并运行,但是我得到一个指针地址打印到我的输出而不是“PARTY DOWN!”串。我确定发生了这种情况,因为编译器选择执行流输出的运算符是 ostream& operator<< (const void* val),而非ostream& operator<< (ostream& out, const char* s )

我对于为什么有一个模糊的想法,但我不知道如何解决它。如何将char * s打印到字符串流的临时实例中?

这是展示行为的SpecialStringStream对象的简短版本:

class SpecialStringStream : public ostringstream
{
  public:
    SpecialStringStream(ostream* regularStream)
    {
      regularStream_ = regularStream;
    }

    ~SpecialStringStream()
    {
      if (regularStream_ != NULL)
        (*regularStream_) << str(); 
    }

  private:
    ostream* regularStream_;
};

当我执行类似:SpecialStringStream(someStreamPtr) << "PARTY DOWN!" << endl;的操作时,我在输出中得到一个指针地址,如“00444D60”,而不是消息。

编辑:由于我是一个太新的用户来回答我自己的问题,这是我已经解决的所有答案。

我提出了以下解决方案,它在Visual C ++ 8和我需要的所有其他编译器下工作。我创建了一个模板操作符,它基本上剥离了const的Const的SpecialStringStream,将其转换为ostream,并让ostream操作符完成它们的操作。请在评论中随意撕碎它,并警告我所引入的所有可怕的潜在错误!

template <class T>
std::ostream& operator<<(const SpecialStringStream &o, T msg)
{
    return static_cast<std::ostream&>(const_cast<SpecialStringStream&>(o)) << msg;
}

4 个答案:

答案 0 :(得分:4)

重载ostream& operator<< (ostream& out, const char*)不可行,因为临时不会绑定到非const引用ostream&。除了声明一个局部变量并使用它之外,没有什么可以做的(因为你不能将左值转换为左值):

{
  specialstringstream ss;
  ss << "Hello world" << std::endl; // OK, can bind to lvalue
}

可能的解决方案:您可以声明另一个接受右值引用的重载:

std::ostream & operator<<(specialstringstream && o, const char * s)
{
  return o << s; // note: *not* "std::move(o)"
}

答案 1 :(得分:2)

您不想实现stringstream。你想实现一个写入你的特殊字符串的basic_streambuf。

流本身负责格式化和类似功能; streambufs负责最终成为数据的接收器。

毕竟,所有的字符串流都是iostream,附带了basic_stringbuf。

答案 2 :(得分:2)

也许有更好的方法,但我想出了另一个解决方案:

#include <iostream>
#include <sstream>

class LogClass
{ 
    template <typename T>
    friend const LogClass& operator << (const LogClass& lc, const T& v);
public:
    LogClass()
        : str(new std::ostringstream())
        , refCount(new int(1))
    {}

    LogClass(const LogClass& other)
        : str(other.str)
    {
        ++(*refCount);
    }

    ~LogClass()
    {
        --(*refCount);
        if (!*refCount)
        {
            delete refCount;
            std::cout << str->str() << std::endl;
            delete str;
        }
    }
private:
    mutable std::ostringstream *str;
    int *refCount;

    LogClass& operator = (const LogClass&);
};

template <typename T>
const LogClass& operator << (const LogClass& lc, const T& v)
{
    (*lc.str) << v;
    return lc;
}

int main(int , char**)
{
    for (size_t i = 0; i < 10 ; ++i)
    {
        LogClass() << "PARTY DOWN! " << i;
    }
}

使用valgrind运行它:

valgrind --tool = memcheck --leak-check = full ./LogClass

== 16197 == Memcheck,内存错误检测器

== 16197 ==版权所有(C)2002-2010,以及Julian Seward等人的GNU GPL,

== 16197 ==使用Valgrind-3.7.0.SVN和LibVEX;用-h重新运行版权信息

== 16197 ==命令:./ LogClass

== 16197 ==

派对下来! 0

派对下来! 1

派对下来! 2

派对下来! 3

派对下来! 4

派对下来! 5

派对下来! 6

派对下来! 7

派对下来! 8

派对下来! 9

== 16197 ==

== 16197 == HEAP SUMMARY:

== 16197 ==在退出时使用:0块中的0字节

== 16197 ==总堆使用量:40个分配,40个释放,7,350个字节分配

== 16197 ==

== 16197 ==所有堆块都被释放 - 没有泄漏可能

== 16197 ==

== 16197 ==对于检测到的和抑制的错误计数,请重新运行:-v

== 16197 ==错误摘要:来自0个上下文的0个错误(被抑制:15个来自8个)

这就是我想要的,但不是线程安全的。使用boost中的shared_ptr来实现它。

答案 3 :(得分:0)

这是我正在使用的解决方法:

#define STRM2STR(x) (dynamic_cast<std::ostringstream &>(std::ostringstream() << std::dec << x).str())

插入std :: dec将导致调用ostream :: operator&lt;&lt; (ios_base&amp;(* pf)(ios_base&amp;))返回可用的ostream&amp;