Thursday, 9 June 2011

Why copy-semantics of stream classes from Standard Library are disabled?

C++ Standard IO Library defines several  stream classes, such as std::istream, std::ostream, std::iostream, std::ifstream, std::ofstream, std::fstream, std::istringstream, std::ostringstream, std::stringstream, and their wide-character counterparts.  Copy-semantic of all these streams has been disabled by having made the copy constructor and copy-assignment private, which means one cannot make a copy of stream object:

std::ifstream file("file.txt"); //okay
std::ifstream acopy = file; //error - attempting to make a copy but copy-ctor is private
std::ifstream bcopy; //okay
bcopy = file; //error - attempting to make a copy but operator= is private
Copying of stream is disabled because it doesn't make sense. Its very important to understand what stream means, in order to completely understand why copying stream object does not make sense. A stream object is not a container that one 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 (or a pipe) through which data flows. Think of stream as some pipe or tube through which you get data; a pipe or tube - one side of which is connected to the actual source (sender),  the other side is having the sink (receiver). That is called unidirectional stream. There are also bidirectional streams through which data flows in both direction, such as network stream (though the Standard library doesn't define any). 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 a program read it twice or more? It cannot, and should not. 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

However, one can create another instance of stream and can make it use the same underlying buffer which the old stream is currently using.

#include <iostream>
#include <sstream>
using namespace std;
 
int main() 
{
        stringstream ss;
        streambuf *coutbuf = cout.rdbuf();
        cout.rdbuf(ss.rdbuf());
        cout << "this goes to the stringstream" << endl;
        string s = ss.str();
        cout.rdbuf(coutbuf);
        cout << "after cour.rdbuf : " << s;
        return 0;
}
Online demo : http://ideone.com/rijov

No comments:

Post a Comment