user425678
user425678

Reputation: 760

Initializing stream in constructor

I'm just starting to learn C++ having come from a C# background.

I am creating a class that will parse CSV data, and I want the class to be initialized with either a filepath or a stream. If a filepath is passed the _str_in should be set to a newly opened ifstream.

My code below compiles but gives a warning on the second constructor "reference member is initialized to a temporary that doesn't persist after the constructor exits". I am guessing the warning relates to the following:

  1. ifstream is created and _str_in is set to reference it
  2. the memory assigned to ifstream is released after the constructor exits
  3. _str_in now points to non-allocated memory and could become corrupted.

I've tried different ways of accomplishing this and checked many SO questions but I'm stumped — any suggestions?

class TokenParser
{
    std::istream& _str_in;
    char _delim;

public:
    TokenParser::TokenParser(std::istream& str_in, char delim) : _str_in(str_in), _delim(delim)
    {
    }

    TokenParser::TokenParser(std::string& file_path, char delim) : _str_in(std::ifstream(file_path)), _delim(delim)
    {
    }

Upvotes: 2

Views: 1935

Answers (2)

Andreas DM
Andreas DM

Reputation: 11028

Try this:
Using universal reference and std::move in <algorithm>

class TokenParser
{
std::istream&& _str_in; // notice the && 'universal reference'
char _delim;

public:
TokenParser::TokenParser(std::istream&& str_in, char delim) 
: _str_in(std::move(str_in)), _delim(delim)
{}
// other ctors...
}

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727077

The problem is pretty much what the compiler describes: the object created by std::ifstream(file_path) will be gone by the time the constructor completes, so the reference _str_in would instantly become dangling.

You could work around this problem by making an std::ifstream object inside TokenParser, and using it when the second constructor is called:

class TokenParser
{
    std::ifstream _file;
    std::istream& _str_in;
    char _delim;

public:
    TokenParser::TokenParser(std::istream& str_in, char delim) : _str_in(str_in), _delim(delim)
    {
    }

    TokenParser::TokenParser(std::string& file_path, char delim) : _file(file_path), _str_in(_file)), _delim(delim)
    {
    }
...
}

Upvotes: 2

Related Questions