Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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;
}
like image 982
Number42 Avatar asked Oct 15 '12 06:10

Number42


2 Answers

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?

like image 176
PaperBirdMaster Avatar answered Oct 08 '22 15:10

PaperBirdMaster


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

A(const A &rhs) : s_(rhs.s_) {cout << "A::copy" << endl;}
like image 23
chris Avatar answered Oct 08 '22 16:10

chris