Search code examples
c++referencecopy-constructordefault-constructor

Why does using a reference member prevent deleted constructor errors?


Context

I have two classes (simplified to the relevant declarations):

#include <string>
#include <fstream>

class Lexer
{
    std::ifstream file_;
    Lexer(std::string &file) : file_(file){};
};

class Parser
{
    Lexer lexer_;
    Parser(Lexer &lex) : lexer_(lex){};
};

This fails to compile with the error

error: use of deleted function 'std::basic_ifstream<_CharT, _Traits>::basic_ifstream(const std::basic_ifstream<_CharT, _Traits>&) [with _CharT = char; _Traits = std::char_traits]'

After eventually finding Error where no default constructor exists for a class I think I now understand:

  • The issue is that ifstream has a deleted default constructor which prevents Lexer from being used in Parser because it's not being supplied a string (whereas the Lexer class itself compiles fine).
  • If I make Lexer take an ifstream directly there's still an error (similar reasoning as above) because it also has a deleted copy constructor.
  • By making file_ a reference member (i.e. std::ifstream &file_;) the lack of copy constructor problem is solved because the member initialiser is no longer attempting to use a copy constructor (since it's just a reference).

My questions are:

  1. Is my understanding correct? It feels a little fuzzy, but I'm new to C++ and still getting used to thinking about the use of reference in different contexts (I understand the general concept).
  2. Why exactly is the lack of a default constructor an issue here, but not when just the Lexer class (as is above) is declared?
  3. Is the use of a reference member the most semantically correct solution here?

Solution

  • ifstream does have a default constructor. The error you pasted it because of the deleted copy constructor. The code you wrote will not work, because Lexer can not be copy constructed with the default, because ifstream is not copyable.

    So, to answer you questions:

    1. Your understanding is incorrect; though not a bad guess.
    2. Not related to default constructor.
    3. Depends what you are trying to do. You may want to prevent copying of Lexer, or make your own copy constructor, or use references.