Alcott
Alcott

Reputation: 18585

cannot assign or copy iostream object?

iostream and other stream class are not actually class, but typedefs, right?

Here is the problem, I tried to initialize a istream object in initialization list, but unfortunately I got an error, code goes bellow:

class A 
{
    public:
        A(istream &is=cin): ais(is)
        {}

    private:
        istream ais;
};

Can't compile with g++, error:

synthesized method ‘std::basic_istream<char, std::char_traits<char> >::basic_istream(const std::basic_istream<char, std::char_traits<char> >&)’ first required here 

I searched SO, found that, iostream cannot be assigned or copy. But why cannot I initialize it in the initialization list?

Cuz I think, the initialization list will invoke the object's constructor/copy-constructor, right?

Upvotes: 3

Views: 5829

Answers (6)

Daniel Lidstr&#246;m
Daniel Lidstr&#246;m

Reputation: 10280

class A 
{
    public:
        A(istream &is=cin): ais(is)
        {}

    private:
        istream& ais;
};

Notice the member is a reference type. As you've written it, you're making a copy to initialize the member.

Upvotes: 1

David Schwartz
David Schwartz

Reputation: 182827

Your code attempts to turn one istream, the one passed to the constructor, into two istreams, the one that was passed to the constructor and ais. An istream object represents that actual stream itself. There is only one stream and there is no way to somehow turn it into two streams.

It's not even clear what that would mean. If there's some data on the stream, does whichever stream reads first get it? Or do they both get it? If so, who or what duplicates it?

An istream is like a file itself. You cannot turn one file into two files without copying the data from one to the other yourself. You can, however, have as many references or pointers to the same istream as you want. The solution to your problem is probably to make ais a reference.

Upvotes: 8

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 154005

The stream object represent a handle to streams of data. Copying that doesn't make sense. Also, this wouldn't be the right thing to copy only tge base part of a stream: this would be slicing off the interesting bit (although you could get hold of thr actually interesting portion by using the stream buffer).

What you want to initialize in your class if it holds a stream is a reference to the stream:

std::istream& ais;

Of course, this means that some external needs to keep the stream alive as long as you are using it. If this isn't what you want or need you can have your class hold e.g. an std::ifstream and take a std::string as constructor argument: if the string is non-empty you'd open the corresponding file. Otherwise you'd set your stream's rdbuf() to the one from std::cin:

if (name.empty())
    ais.open(name.c_str());
else
    ais.rdbuf(std::cin.rdbuf());

Upvotes: 2

celtschk
celtschk

Reputation: 19731

In addition to the answers you already got, you can also initialize ais (as of your definition) with the streambuf of the stream you passed in (of course, the same caveat as with the reference applies: You must ensure that the streambuf stays valid until the object is destructed).

Initializing with the underlying streambuf is probably the closest to copying a stream you can do: While both still read from the same file and use the same buffering (and other processing the streambuf may do), all the formatting and error handling flags are separate.

To initialize ais with the streambuf, you write:

class A 
{
public:
  A(std::istream& is = std::cin):
    ais(is.rdbuf())
  {
  }
private:
  std::istream ais;
};

Upvotes: 1

hmjd
hmjd

Reputation: 122001

You have the member variable declared as:

istream ais;

meaning the copy constructor will be invoked in the initializer list. This is not specific to the initializer list: you can't do this anywhere.

You could change the member variable to be a reference:

istream& ais;

but that means you have to ensure that the istream to which ais refers is valid for the lifetime of A.

Upvotes: 5

Cat Plus Plus
Cat Plus Plus

Reputation: 129914

iostream and other stream class are not actually class, but typedefs, right?

Yes, but that's not relevant.

But why cannot I initialize it in the initialization list?

Because it can be neither copied nor assigned. Ctor init list is not magical. To create ais from is you need to make a copy, and you can't.

Upvotes: 3

Related Questions