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;
}
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 A
constructor 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?
Your copy constructor never initializes the reference. Make sure it does:
A(const A &rhs) : s_(rhs.s_) {cout << "A::copy" << endl;}
string& s_;
This is an referance variable. It should have an value when the object is alocated because this is a part of the object, this is why the initialisation list of constructor should be used to initialize this atribute.
If you don't need to have this atribute like a part of the object you can use a pointer instead of referance :
string* s_;