为什么无法创建流缓冲区的副本? [英] Why can't I create a copy of a stream buffer?

查看:140
本文介绍了为什么无法创建流缓冲区的副本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我有这个类:

  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<< 你好;

如果 buf c $ c> cout 的缓冲区,为什么它不打印任何东西?

解决方案

在流缓冲区的规范中没有说如果你以这种方式复制流缓冲区,那么复制将继续从同一设备读/写,也不是 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; //非拥有指针

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!\\\
;
}






cout 使用的缓冲区。如果你这样做,你应该确保把 cout 在程序结束时销毁,因为 cout $ c>管理自己的流缓冲区的生命周期,当 cout 的析构函数运行时,它可能需要它持有的流缓冲区是它最初创建的流缓冲区。

  //用于管理缓冲区交换机的RAII类型。 
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(){
//创建我们的转发缓冲区
copiable_streambuf buf(std :: cout.rdbuf());

//设置cout以使用我们的缓冲区并同时确保缓冲区将根据需要切换回
buffer_switcher _(std :: cout,& buf);

std :: cout<< 你好;
}


When I have this class:

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

That compiles but when I try to do this nothing prints out:

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

std::cout << "Hello";

If buf is a copy of cout's buffer, why then does it not print anything?

解决方案

There's nothing in the specification for stream buffers that says if you copy a stream buffer this way then the copy will continue to read/write from the same device, nor is cout specified such that its result from rdbuf() will behave as you desire.

streambuf is essentially an interface, and its copy constructor does not somehow virtually invoke the copy constructor of any class implementing the interface. Polymorphic types can't be held, copied, passed, etc. by value. In order to copy a polymorphic type you have to use something like a virtual clone() member function, and the streambuf interface does not include any such method.

In order to copy the streambuf used by cout you would have to access it using its dynamic type, and even then it might not be copiable: For example, it might be that multiple stream buffers accessing the same device would need to coordinate or synchronize in some fashion, and a streambuf implementation may disallow copying so that it can safely avoid having to do that synchronization.


What I'm trying to do is create a stream buffer with all the characteristics of std::cout's stream buffer, but with extra member functions built in (for my use). Would you know how to do that?

What extra characteristics are you trying to add? It may be that implementing streambuf is not the appropriate place to add your functionality.


If you want an implementation of the streambuf interface that forwards to a preexisting streambuf then you can create a streambuf class which holds a streambuf pointer, properly treating it as a pointer to a polymorphic type, and implementing the streambuf interface by forwarding calls to the internal streambuf. This is a really simple implementation:

#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";
}


Your example code involves replacing the buffer used by cout. If you do this you should be sure to put the original buffer back before cout is destroyed at the end of the program, because cout manages the lifetime of its own stream buffer and when couts destructor runs it may require the stream buffer it's holding to be the one it originally created.

// 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";    
}

这篇关于为什么无法创建流缓冲区的副本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆