Why I can't just create an "empty" stream for my output like this
std::ostream out;
?
This rows is apparently illegal with both clang 3.4
and gcc 4.8.1
under linux with libstdc++
, I really don't get why, I mean why I can't just create a stream out of nowhere and use it like I want to ? notice that std::ofstream out;
is 100% ok instead. I just don't get the logic behind this. This is even stranger if you consider that after the creation I can just use this buffer and share a common buffer with other buffers with copyfmt
so there is no real need for my std::ostream
to be initialized to something right from the creation of the object to be useful.
Please don't deviate from this, I don't need stringstreams
, I need ios
streams because of what I have to do and because of the methods and the properties that they are offering.
I'll admit that I don't understand it either. I can't find any default constructor at all for std::istream
, and I would think you would want one if you want to create a bidirectional stream, because of the strange way std::ios_base
works: the constructor does not initialize anything, but the derived class must call std::ios_base::init
explicitly in its constructor. When multiple inheritance is involved (ie bidirectional IO, where the class derives from both std::istream
and std::ostream
), I would expect only the most derived class to call std::ios_base::init
. (In std::iostream
, std::ios_base::init
will be called twice.) In fact, before looking it up in the standard, I was about to answer that the default constructor was protected, because it didn't call std::ios_base::init
, and using it directly, rather than in a derived class, would result in an uninitialized stream.
Anyhow, your immediate problem has a simple solution:
std::ostream out( NULL );
Also: the function you need to set up its sink later is the non-const version of rdbuf()
, not copyfmt()
. rdbuf()
is used to read and to set the pointer to the streambuf
, copyfmt()
copies the formatting flags, but does not touch the pointer to streambuf
.
So you can do things like:
std::ostream out( NULL );
// ...
std::filebuf fileBuffer;
if ( filenameGiven ) {
fileBuffer.open( filename.c_str(), std::ios_base::out );
}
if ( fileIsOpen() ) {
out.rdbuf( &fileBuffer );
} else {
out.rdbuf( std::cout.rdbuf() );
}
(I do this a lot. In fact, I thought that it was the usual idiom when you didn't know up front whether to output to a file or to std::cout
.)
EDIT:
And yet another correction: the non-const version of rdbuf
calls clear()
, so you don't have to. (I knew I'd done this without calling clear()
, but when I saw that init
set badbit
...)
Anyhow: the summary is: it's usually preferrable to pass a pointer to a valid streambuf to the constructor of std::ostream
, but if you can't, it's perfectly valid to pass a null pointer, and set a valid pointer later using rdbuf()
. And the answers which say otherwise are simply wrong.
std::ostream
is conceptually abstract - you're not supposed to create them (but see other answers for more detail on that).
std::stringstream
gives you everything std::ostream
does because it derives from it. This also means that anywhere you want an std::ostream&
, for example in function arguments, you can pass a std::stringstream
object.
You say "there's no need for [it] to be initialised [...] to be useful". That makes no sense at all. You cannot use anything that hasn't been initialised: even int
s.
The default constructor of std::basic_ostream
is protected
because it generally doesn't make any sense to create an std::basic_ostream
without setting its std::basic_streambuf
and the default constructor actually doesn't do any initialization (see below). There is, however, another constructor taking a stream buffer as argument. If you really need an std::ostream
which isn't set up to do anything, yet, you can use that constructor:
std::ostream out(0);
This std::ostream
will have the std::ios_base::badbit
set until a stream buffer is set up using std::ios::rdbuf()
.
The underlying reason for std::ostream
's default constructor being protected
is that it actually deliberately doesn't do anything useful! In particular, calling this constructor [from a further derived class] will not initialize the stream buffer at all: the standard doesn't mandate any behavior explicitly, ie, the default constructor has implicitly the behavior of the generate default constructor (or, in C++2011 as if it is defined using = default
). To get the stream buffer initialized, it would need to call std::ios::init()
. The reason for this odd behavior is that constructing an object of the further derived class std::iostream
would initialized the std::ios
object twice, once through std::ostream
and once through std::istream
.
Unlike some of the other answers suggest, std::ostream
isn't abstract at all. In fact, it only has exactly one virtual
function anyway and that is its destructor (the destructor being virtual
happens to be my fault; I'm not entirely convinced that it was really a good idea to force that).
stringstream
is an ios
stream.
But about your question:
An ostream
writes somewhere. if you declare
std::ostream out;
out << "Hello, world!"<<std::endl
the "Hello, world!"
should be written somewhere. But where? That depends on the implementation for each specific ostream
. Yes, there is a buffer, but that buffer also depends on the specific implementation.
So when you say "I want an ostream
" I have to ask - one which writes stuff... to where?
Given your answer, that will tell me which specific instance/implementation of ostream
you need to use.
The std::ostream is a generalized stream class. Because of that it has no way of knowing what it is streaming to, which is the whole point of having a generalized class.
When you send data to a stream it doesn't actually store the data itself. It simply passes it forward to an associated buffer. Taking this into consideration, creating a generalized stream without assigning this buffer to it makes no sense, as the generalized class cannot create an empty generalized buffer. (The buffer itself needs to be a buffer of a concrete type, which is also understood by looking at the generalized buffer std::treambuf that doesn't have a public consstructor at all)
Compare this with the std::ofstream, which is a stream with a specific type of buffer, it is now possible for the ofstream to know what kind of buffer it uses, thus being able to instantiate a default std::filebuf.
To solve your concrete problem.
Create the buffer of your wanted type first, and then create the a generalized std::ostream with the buffer as a parameter. You can then at a later point connect to a file using std::filebuf::open().
Example:
std::filebuf fileBuffer;
std::ostream myOstream(&fileBuffer); // Hand over the address of the fileBuffer
fileBuffer.open("filename.txt", std::ios::out);
myOstream << "Text to file";
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.