2010-12-04 1 views
2

Возможно ли, чтобы поток streambuf сохранился после разрушения разрушения его исходного потока?Имея поток streambuf потока упорства за разрушение потока?

streambuf* f() { 
    ifstream my_stream; 
    // ... 
    return my_stream.rdbuf(); 
} 

void g() { 
    streambuf *s = f(); 
    // ... 
    ifstream my_new_stream; 
    my_new_stream.rdbuf(s); 
} 

Т.е., я хочу указатель на streambuf объекта, возвращенного f() остается в силе даже после того, как my_stream выходит из области видимости. В какой-то более поздний момент я хочу установить другого потока в сохраненный streambuf.

Возможно ли это? Если да, то как?

+2

Почему вы хотите это сделать? Почему вы не можете просто сохранить ссылку на `ifstream`? – casablanca 2010-12-04 17:18:10

ответ

2

Невозможно. std::ifstream строит, владеет и уничтожает свой буфер. Единственная причина, по которой он «экспортируется» через rdbuf, - это перенаправление std::cin и т. Д. В реализации GNU буфер представляет собой простой элемент (а не указатель).

std::ifstream не экспортирует член rdbuf() с аргументом. Один из его родительских классов делают, но это должно быть омрачено переопределением rdbuf в std::basic_ifstream с подписью

std::filebuf *rdbuf() const; 

std::filebuf также не-копируемая.

(The rdbuf(std::streambuf *) элемент может быть получен путем отливки в std::ios. Используя это приведет знакомые носовых демонов.)

1

Чтобы получить то, что вы хотите, создавать и управлять filebuf/streambuf для себя. Вы можете создавать istreams или ostreams на streambuf по мере необходимости.

Как следующее:

#include <iostream> 
#include <fstream> 
#include <memory> 
#include <string> 

using namespace std; 

shared_ptr<streambuf> f() 
{ 
    auto ret = make_shared<filebuf>(); 
    if(!ret->open("filebuf-test.cpp", ios::in)) 
     exit(1); 
    return ret; 
} 

void g(streambuf *sb) 
{ 
    istream is(sb); 

    string line; 

    while(getline(is, line)) { 
     cout << line << '\n'; 
    } 
} 

int main() 
{ 
    auto p = f(); 
    g(p.get()); 
    return 0; 
}