5

std::ostream has no member function close(). What type of stream should I not be allowed to close?

As an example, maybe I would like to close std::cout in order to prevent any further writing to it.

std::cout.close(); // ‘std::ostream’ has no member named ‘close’

If I were using the C library, I could close stdout with:

fclose(stdout); // no problem

So what is the idea behind leaving out the close() member from std::ostream?


Related:

Community
  • 1
  • 1
Brent Bradburn
  • 51,587
  • 17
  • 154
  • 173
  • 5
    `ostream` is an abstraction, it doesn't have `close` or `open` because not all streams (or rather their underlying buffers) can be closed or opened, as you can see. For what it's worth `fclose(stdout);` will still work in C++ because `cout` is explicitly associated with `stdout`. – user657267 May 28 '15 at 01:43
  • 2
    It makes perfect sense to close an ostream -- it means that no more output should be sent to it, and any attempt to do so should set the error flag on the stream... – Chris Dodd Sep 05 '18 at 21:41
  • Interesting: The destructor of [`ofstream`](https://en.cppreference.com/w/cpp/io/basic_ofstream) is described as _'implicitly declared'_, while being _explicitly_ documented to close the file. I don't know see how this would work unless (it's parent) [`ostream`](https://en.cppreference.com/w/cpp/io/basic_ostream) has a virtual `close` (maybe indirectly). – Brent Bradburn Dec 17 '19 at 13:22

3 Answers3

5

It does not make sense to have the close() function as a member of std::ostream. The first example would be that std::ostringstream inherits from std::ostream. Would it make sense to close a string? The only members of std::ostream are the global objects for input/output.

The filestreams have a close() function because it is important to be able to release the resource to the environment. However, since there are other classes that inherit from this base class that don't need this function, it wouldn't make sense for it to be a part of std::ostream and that's why it is only used in the filestreams.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
meneldal
  • 1,717
  • 1
  • 21
  • 30
  • 2
    Makes sense, except that I don't see why `std::ostringstream` shouldn't be closable. Unlike `open()`, which is clearly tied to the specific subclass, `close()` is a very generic operation that could be meaningful on any type of stream -- it just means that you are done writing and any future write operations should probably return an error. Conceptually, it's at least as generic as `flush()`, which `ostream` does provide. But you're right -- `close()` is more *necessary* for some types of streams than others. – Brent Bradburn May 28 '15 at 02:24
  • If you're done writing to the string, you should just query the string out of the item. I do admit most of my use of the stirngstreams are for things like that: `std::string intToStr(int i){ std::ostringstream temp; return (temp << i), temp.str();}` Where the enclosing scope make it clear when the stream itself is closed. Flushing is a way to tell the underlying stream that you should empty your current write buffer and write to the actual stream so it's different. In my opinion `close()` itself is not really necessary even for files anyway. – meneldal May 28 '15 at 02:39
  • Since when is `ostream`'s (normal) constructor deleted? – T.C. May 28 '15 at 03:33
  • I forgot the import part. It's the copy constructor not the constructor. – meneldal May 28 '15 at 03:35
  • @meneldal Although for a simple `intToStr()`, you could just use `std::to_string()` (since C++11). – Alexis Wilke Jan 24 '20 at 03:56
  • @AlexisWilke very good point, I didn't think about that at all, I'm not sure if I knew about it at the time. I don't use streams much, and with C++20 hopefully I'll never need stringstreams again because we get a better replacement. – meneldal Feb 05 '20 at 05:29
2

Here's a way to fake it out:

void ostream_fake_close( std::ostream & os )
   {
   os.flush();
   static std::stringstream closed_flag;
   cerr<<(os.rdbuf()==closed_flag.rdbuf()?"closed":"open")<<"\n";
   os.rdbuf(closed_flag.rdbuf());
   cerr<<(os.rdbuf()==closed_flag.rdbuf()?"closed":"open")<<"\n";
   }

Future writes to the stream will be redirected into the closed_flag buffer. You can limit the buffer's size by periodically resetting it:

closed_flag.str("");

The real close will be issued automatically when the object is destructed.

Community
  • 1
  • 1
Brent Bradburn
  • 51,587
  • 17
  • 154
  • 173
0

In addition to Meneldal's excellent answer.

Not releasing the resource could still cause problems for some types of resources if you need to access them later. If for some reason you do not want to use ofstream (which has a close method), and stick with ostream. You can just let it go out of scope.

Example:

std::string FilePath = "C:/Test/MyFile.ext";

{  // <== Note the start of scope.

        // Writing a file using ostream as by example given by cplusplus.com reference.
        std::filebuf outfb;
        outfb.open(FilePath, std::ios::out);
        std::ostream os(&outfb);

        /* Do your stuf using 'os' here. */

}  // <== Note the end of scope.

/* Here, the resource is freed as if you would have called close. */
/* Rest of code... */

UPDATE : However, now I think about it, in this case std::filebuf provides the close method which would also solve your problem.

Stefan
  • 919
  • 2
  • 13
  • 24