56
int main()
{
   std::stringstream s1("This is my string.");
   std::stringstream s2 = s1; // error, copying not allowed
}

I couldn't find a reason as to why i can't copy stringstream. could you provide some reference?

Nawaz
  • 353,942
  • 115
  • 666
  • 851
user756327
  • 591
  • 1
  • 4
  • 5
  • 8
    In case you are not aware of this, you can effectively achieve a copy using `std::stringstream s2(s1.str());`. – Björn Pollex May 15 '11 at 20:03
  • 7
    @Space: I think this would be more appropriate: `std::stringstream s2; s2 << s1.rdbuf();`. – GManNickG May 15 '11 at 22:21
  • @GManNickG Doesn't this has a lower performance? – StanE Jun 15 '16 at 06:55
  • @StanE: Than...what? Than the previous comment? I don't think so. You'd need to measure to be sure. – GManNickG Jun 15 '16 at 15:47
  • @GManNickG Yes, your example with the shift operator compared to the constructor version from previous comment. I just ask because I'm new to this and I'm interested to know if the performance is different. I would think that using the contructor might be faster, since there is no conversion for different types and space must be allocated only once, etc. But I'm not sure. Just interested to know. – StanE Jun 18 '16 at 14:45
  • 1
    @StanE: The only way to be sure is to measure. :) – GManNickG Jun 18 '16 at 16:41

3 Answers3

88

Copying of ANY stream in C++ is disabled by having made the copy constructor private.

Any means ANY, whether it is stringstream, istream, ostream,iostream or whatever.

Copying of stream is disabled because it doesn't make sense. Its very very very important to understand what stream means, to actually understand why copying stream does not make sense. stream is not a container that you can make copy of. It doesn't contain data.

If a list/vector/map or any container is a bucket, then stream is a hose through which data flows. Think of stream as some pipe through which you get data; a pipe - at one side is the source (sender), on the other side is the sink (receiver). That is called unidirectional stream. There're also bidirectional streams through which data flows in both direction. So what does it make sense making a copy of such a thing? It doesn't contain any data at all. It is through which you get data.

Now suppose for a while if making a copy of stream is allowed, and you created a copy of std::cin which is in fact input stream. Say the copied object is copy_cin. Now ask yourself : does it make sense to read data from copy_cin stream when the very same data has already been read from std::cin. No, it doesn't make sense, because the user entered the data only once, the keyboard (or the input device) generated the electric signals only once and they flowed through all other hardwares and low-level APIs only once. How can your program read it twice or more?

Hence, creating copy is not allowed, but creating reference is allowed:

std::istream  copy_cin = std::cin; //error
std::istream & ref_cin = std::cin; //ok

Also note that you can create another instance of stream and can make it use the same underlying buffer which the old stream is currently using. See this : https://ideone.com/rijov

Gabe
  • 84,912
  • 12
  • 139
  • 238
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • @Nawaz - Any reason for making the copy constructor **private** ? – Mahesh May 15 '11 at 20:12
  • @Mahesh: Yes. Let me explain it in the answer itself. – Nawaz May 15 '11 at 20:12
  • @Mahesh: Now read the edited answer. Now it explains this in detail. – Nawaz May 16 '11 at 05:32
  • will 2 streams sharing the same buffer have an independent state (e.g. current position)? In other words, is the state a property of the buffer or a stream? Both ways seem awkward: 1) independent state - suppose one stream consumed the whole buffer and needs a "refill" while the other did not; 2) shared state - seems like both streams tear pieces of data from each other hands. So I don't see what it can be useful for – davka May 16 '11 at 06:06
  • 1
    @davka: The buffer is of course shared. Read from one and it will be missing from the other. – Xeo May 16 '11 at 06:16
  • 3
    The 'hose' metaphor is nice, but then where is that data that I put into a std::stringstream ending up then? There must be a default bucket connected to that hose, as I can get the content of that bucket by doing a e.g. std::stringstream::str(). – Chaos_99 Sep 02 '13 at 09:14
  • @Chaos_99: It is the other end which is receiving (or rather reading) from the stream, e.g in the context of *input* stream, an operation like `std::cin >> data` describes the receiving end. – Nawaz Sep 02 '13 at 09:43
  • 2
    I don't see how anything you say is different for iterators and streams, yet you can copy iterators but not streams. – user541686 Apr 18 '14 at 04:48
  • 1
    @Mehrdad: The design of iterators is based on pointer-semantic (pointers are iterators, remember?). That is why iterators are copyable because pointers are copyable! You can still selectively disable copy for iterators of certain category (say input iterators), but that would introduce complexity and inconsistency to the design. for example, random access iterators (such as pointers) are input iterator too. – Nawaz Apr 18 '14 at 05:00
  • 4
    I understand perfectly why iterators are copyable, I'm not asking or complaining about that. I'm saying that streams could be copyable in exactly the same way with exactly the same result, yet they aren't... which means your answer is probably wrong because there's no real reason why they couldn't have the same semantics as pointers upon copying. – user541686 Apr 18 '14 at 06:48
  • 1
    @Mehrdad: The answer is same: to avoid (unnecessary) complexity. Not convinced? Try to implement your own copyable stream classes. – Nawaz Apr 18 '14 at 07:00
  • 1
    @Nawaz: Uh, no, it's not "the same". Saying it's *"to avoid complexity"* is ***very*** different from saying *"it doesn't make sense"*. If you now realized it *does* make sense (and it seems you did), then it's worth changing your answer, because currently it's wrong -- it *does* make sense, it's just not as easy to implement as for iterators. – user541686 Apr 18 '14 at 07:39
  • @Mehrdad: I've to prove the complexity in order to say it. Moreover, the name *stream* is so chosen because it acts like it, in which case, *copy* indeed doesn't make sense. Both are true at the same time. "Water is usually liquid" doesn't contradict "it is H2O". – Nawaz Apr 18 '14 at 08:23
  • .... Also, remember that, *first* it doesn't make sense if you go by its name (and how it behaves), then comes the complexity factor (which is not worth adding). Copyable iterator also doesn't make much sense, because it does NOT really copy. it is supported anyway, because pointers intrinsically support it (so in this case, not supporting it adds complexity and inconsistency). Hope that makes sense now. – Nawaz Apr 18 '14 at 08:30
  • Honestly it's not as ridiculous of an idea as you make it seem, but I don't have any way to convince you so... – user541686 Apr 18 '14 at 08:39
  • One way to copy a stream like cin would to have them all have independent iterators to a shared list of received input. I don't see another way because a single copy may undecidably never read its input. This means memory would grow with each read. Disk writes could be used for storing the list data. All in all, this seems exploitable. Keep in mind that I don't necessarily agree that streams are not copy constructible. Let each class instance decide. – Thomas Eding Jun 27 '14 at 06:46
  • 1
    I'm still not convinced why you can't make a copy of a 'storing' sink of a stream. `myStream(myStream& src){ localstore << src.localstore.str(); }`. StringStream type variables would be perfectly capable of acting that way. – SF. May 13 '16 at 10:07
4

To directly answer the question, you can't copy because the copy constructor for the stringstream class is declared as private.

It was probably declared that way because it seems awkward to copy a stream in most cases, so none of the stream classes have public copy constructors.

Himadri Choudhury
  • 10,217
  • 6
  • 39
  • 47
4

As mentioned above you cannot copy stream, but if you need you could copy data:

std::stringstream from;
std::stringstream to;

std::copy(std::istream_iterator<char>(from), std::istream_iterator<char>(),
          std::ostream_iterator<char>(to));
tvn
  • 634
  • 3
  • 6