Fred
Fred

Reputation: 4076

Error initializing non-const type in constructor initializer?

The error:

error: invalid initialization of non-const reference of type ‘std::istream& {aka std::basic_istream<char>&}’ from an rvalue of type ‘std::ifstream {aka std::basic_ifstream<char>}’

the code:

class MyClass {
private:
  // why does this need to be a const reference?
  std::istream &fin;
};


MyClass::MyClass(std::string &filename,const char quote, const char sep)
  : fin(std::ifstream(filename)), owns_stream(true), sep(sep), quote(quote)
{
}

This works if I make the private fin member const. Can someone explain why?

Upvotes: 2

Views: 166

Answers (1)

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385385

Because you're initialising a reference from a temporary. Only const references can do that … though it actually doesn't "work", because you have a dangling reference. This particular usage of reference-binding will not extend the temporary's life.

[C++14: 12.2/5]: [..] The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:

  • A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits.
  • [..]

The conventional way to do this is to accept a stream into the constructor in the first place:

MyClass(std::istream& strm, const char quote, const char sep)
  : fin(strm), owns_stream(true), sep(sep), quote(quote)
{}

Then:

std::ifstream ifs("/tmp/something");
MyClass obj(ifs);

This is far more flexible for your users.

Otherwise, if you wish to mandate the use of std::ifstream specifically, just store an actual std::ifstream and drop the entire temporary/reference business:

class MyClass {
public:
   MyClass(const std::string& filename)
      : fin(filename)
   {}

private:
  std::ifstream fin;
};

Upvotes: 3

Related Questions