-1

In C++, std::basic_iostream's copy- and move-assignment operators are protected (for reasons I don't really understand). This seems to leave me without many ways of managing a collection of iostream objects, short of manually allocating them on the heap, storing a list of pointers, and writing a destructor that cleans them up.

Am I missing some trick that would let me allocate them inside of, say, a std::vector?

Of course I suppose I could inherit and just promote the protected operator to public, but that seems like a whole mess.

Bonus question: Why are these methods is the move-assignment operator protected in the first place?

Fureeish
  • 12,533
  • 4
  • 32
  • 62
Daniel McLaury
  • 4,047
  • 1
  • 15
  • 37
  • 3
    Thanks for the downvote, but could you explain *why* you downvoted? – Daniel McLaury Feb 21 '19 at 17:21
  • Do you know the number of streams at compile time? – πάντα ῥεῖ Feb 21 '19 at 17:26
  • @πάνταῥεῖ: I don't. – Daniel McLaury Feb 21 '19 at 17:26
  • 3
    Still requires dynamic allocation but `std::vector>` keeps you from having to do an manual memory management. – NathanOliver Feb 21 '19 at 17:27
  • Regarding your _"Bonus question"_ see https://stackoverflow.com/questions/7903903/c-copy-a-stream-object – πάντα ῥεῖ Feb 21 '19 at 17:28
  • 1
    Try to think about what it logically means, to copy an input or an output stream. It makes no sense, whatsoever. Are both input streams, the original one, and the copy, reading from the same file? Same file position? Different file positions? What about if the underlying input stream is a pipe? What about all the internal buffering input streams do, via `std::streambuf`? Ditto for output streams. Big mess. And that's why you cannot copy them. – Sam Varshavchik Feb 21 '19 at 17:28
  • @DanielMcLaury _"I don't"_ Well I can't see any way without involving heap allocation then. – πάντα ῥεῖ Feb 21 '19 at 17:30
  • 1
    Related question [Why can't std::ostream be moved?](https://stackoverflow.com/questions/20774587/why-cant-stdostream-be-moved). – François Andrieux Feb 21 '19 at 17:32
  • Streams are movable, but you can't store base classes by value. A `std::basic_iostream` is a base type and having an actual `basic_iostream` (as opposed to a concrete type like `ofstream` posing as a `basic_iostream`) would not make sense If you want to do that, you fall into polymorphism where you pretty much have to use dynamic allocation (usually `std::unique_ptr`s). – François Andrieux Feb 21 '19 at 17:34
  • @FrançoisAndrieux: It's not an abstract class, and I've been constructing and using `std::iostream` instances directly in my code. Is there some reason I shouldn't? – Daniel McLaury Feb 21 '19 at 17:37
  • @DanielMcLaury I mean, it'll compile and work. But as you noticed from the protected members it's really designed to be derived. My impression was that you were asking for a container to store instances of derived types, but I guess I misunderstood. – François Andrieux Feb 21 '19 at 17:41
  • @FrançoisAndrieux: If you write that up as an answer I'll accept it. – Daniel McLaury Feb 21 '19 at 17:46

3 Answers3

1

Can I store a collection of iostreams anywhere other than the heap?

The only standard container that doesn't allocate dynamically is std::array. You can store iostream's in an array:

std::stringbuf sb;
std::array streams{
    std::iostream(&sb),
    std::iostream(&sb),
};
eerorika
  • 232,697
  • 12
  • 197
  • 326
0
#include <fstream>
#include <vector>

int main()
{
  std::vector<std::fstream> * v = new std::vector<std::fstream> (2);

  (*v)[0].open("/tmp/0", std::ios_base::out);
  (*v)[1].open("/tmp/1", std::ios_base::out);

  (*v)[0] << "000" << std::endl;
  (*v)[1] << "111" << std::endl;

  delete v;
}

Compilation and execution:

pi@raspberrypi:/tmp $ g++ -pedantic -Wextra s.cc
pi@raspberrypi:/tmp $ rm -f 0 1
pi@raspberrypi:/tmp $ ./a.out
pi@raspberrypi:/tmp $ ls -l 0 1
-rw-r--r-- 1 pi pi 4 févr. 21 18:39 0
-rw-r--r-- 1 pi pi 4 févr. 21 18:39 1
pi@raspberrypi:/tmp $ cat 0 1
000
111
bruno
  • 32,421
  • 7
  • 25
  • 37
0

For the sake of closing this out, I'll summarize François Andrieux's comments, which add up to a resolution to the question:

Even though std::iostream is not an abstract class and can be instantiated and used, it's not intended to be; instead, you're supposed to inherit from it to build your own streams. You can then implement move constructors and put these into a std::vector or whatever you want.

Daniel McLaury
  • 4,047
  • 1
  • 15
  • 37