Question

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.

Was it helpful?

Solution

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 (i.e. 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.

OTHER TIPS

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 ints.

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, i.e., 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";
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top