为什么我不能创建流缓冲区的副本?

时间:2014-01-15 21:04:15

标签: c++

当我上课时:

class mystreambuf : public std::streambuf
{
public:
    mystreambuf(const std::streambuf& other) : std::streambuf(other)
    {
    }
};

编译,但当我尝试这样做时,没有打印出来:

mystreambuf buf(*std::cout.rdbuf());
std::cout.rdbuf(&buf);

std::cout << "Hello";

如果bufcout缓冲区的副本,为什么它不会打印任何内容?

1 个答案:

答案 0 :(得分:3)

流缓冲区规范中没有任何内容表明如果以这种方式复制流缓冲区,则复制将继续从同一设备读取/写入,而cout也未指定为rdbuf()的结果将按您的意愿行事。

streambuf本质上是一个接口,它的复制构造函数不会以某种方式虚拟地调用实现该接口的任何类的复制构造函数。多态类型不能按值保存,复制,传递等。为了复制多态类型,您必须使用类似虚拟clone()成员函数的东西,而streambuf接口不包含任何此类方法。

为了复制cout使用的streambuf,您必须使用其动态类型访问它,即使这样,它也可能无法复制:例如,可能是多个流缓冲区访问同一设备需要以某种方式协调或同步,并且streambuf实现可能会禁止复制,以便它可以安全地避免必须进行同步。


  

我尝试做的是创建一个具有std :: cout流缓冲区的所有特性的流缓冲区,但内置了额外的成员函数(供我使用)。你知道怎么做吗?

您想要添加哪些额外的特征?实施streambuf可能不适合添加您的功能。


如果你想要一个转发到预先存在的streambuf的streambuf接口的实现,那么你可以创建一个streambuf类,它保存一个streambuf指针,正确地将它作为指向多态类型的指针,并通过转发调用实现streambuf接口到内部的streambuf。这是一个非常简单的实现:

#include <iostream>

struct copiable_streambuf : std::streambuf {
    std::streambuf *buf; // non-owning pointer

    copiable_streambuf(std::streambuf *buf) : buf(buf) {}

    std::streambuf::int_type overflow(std::streambuf::int_type c) {
        buf->sputc(c);
        return 0;
    }
};

int main()
{
    copiable_streambuf buf (std::cout.rdbuf());
    std::ostream os(&buf);
    os << "Hello, World!\n";
}

您的示例代码涉及替换cout使用的缓冲区。如果你这样做,你应该确保在程序结束时销毁cout之前放回原始缓冲区,因为cout管理自己的流缓冲区的生命周期以及cout s析构函数运行它可能需要它保持的流缓冲区是它最初创建的缓冲区。

// RAII type for managing buffer switches.
struct buffer_switcher {
    std::ostream &os;
    std::streambuf *old;

    buffer_switcher(std::ostream &os, std::streambuf *buf)
        : os(os), old(os.rdbuf())
    {
        os.rdbuf(buf);
    }

    ~buffer_switcher() { os.rdbuf(old); }
};

int main() {
    // create our forwarding buffer
    copiable_streambuf buf(std::cout.rdbuf());

    // set up cout to use our buffer and simultaneously ensure that the buffer will get switched back as required
    buffer_switcher _(std::cout, &buf);

    std::cout << "Hello";    
}