Reference variable with error, must be initialized in constructor base/member initializer

23,954

Solution 1

First of all, your A::s_ is a reference to a std::string; that means that it's referencing something that must exists somewhere.

Due of his reference type, and the fact that the references must be initialized at the moment they're created, you must initialize A::s_ in ALL the A constructors (as pointed by other users):

class A
{
public:
    A(string& s) : s_(s)
    { cout << "A::ctor" << endl; }

    A(const A& rhs) : s_(rhs.s_) // <-- here too!!
    { cout << "A::copy" << endl; }

    ~A()
    { cout << "A::dtor" << endl; }

    A& operator=(const A& rhs)
    { cout << "A::copyassign" << endl; }

private:
    string& s_;    
};

And now, back to the first thing I mentioned; the A::s_ must reference something that exists, so you must be aware of some things, take a look at the following code:

int main()
{
    // New A instance:
    A a("hello world");

    return 0;
}

Constructing this A instance we're providing a const char[12] value, with this value a temporary std::string is created and is given to the A::A(string& s) constructor. Where A::s_ is referencing after the constructor ends? What happens with the temporary std::string created? It's lifetime is extended or it just die when the Aconstructor ends? Are you sure that a reference is what you need?

std::string s("hello world");

int main()
{
    // New A instance:
    A a(s);

    return 0;
}

With the code above, a new A instance is created calling the same A::A(string& s) constructor, but with a provided string lying in the global scope, so it doesn't be destroyed and the A::s_ from the a instance would reference a valid string all its lifetime, but the real threat is in the copy constructor:

std::string s("hello world");

int main()
{
    A a(s);    // a.s_ references the global s.
    A b(a);    // b.s_ references the a.s_ that references the global s.

    return 0;
}

The copied object value will reference the std::string of the given object! Is that what you want?

Solution 2

Your copy constructor never initializes the reference. Make sure it does:

A(const A &rhs) : s_(rhs.s_) {cout << "A::copy" << endl;}
Share:
23,954
Number42
Author by

Number42

I am just a hobbycoder.

Updated on February 04, 2020

Comments

  • Number42
    Number42 over 4 years

    I got following error when I try to compile the source-code below. Can anybody describe why this error exists and how I can fix it?

    Error 1 error C2758: 'A::s_' : must be initialized in constructor base/member initializer

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class A
    {
    public:
        A(string& s) : s_(s) { cout << "A::ctor" << endl; }
        A(const A& rhs)      { cout << "A::copy" << endl; }
        ~A()                 { cout << "A::dtor" << endl; }
    
        A& operator=(const A& rhs) { cout << "A::copyassign" << endl; }
    
    private:
        string& s_;    
    };
    
    int main()
    {
    
        return 0;
    }
    
  • Number42
    Number42 over 11 years
    Thanks a lot for the detailed description.
  • chris
    chris over 11 years
    I just want to point out that you can't pass "hello world" into it in the first place (i.e. compiler error) as temporaries can't be bound to a non-constant reference.
  • PaperBirdMaster
    PaperBirdMaster over 11 years
    @chris it worked for me. The temporary created at the A a("hello world") call is bounded to the a.s_ reference.
  • PaperBirdMaster
    PaperBirdMaster over 11 years
    My bad! you're right! silly me! :( this proves that make std::string references as members and make a non-explicit constructor is even worse than i thought!