Initialize link in initialization list

I was told that the reference variable should be initialized in the initialization list, but why is this wrong?

class Foo { public: Foo():x(0) { y = 1; } private: int& x; int y; }; 

Because 0 is a temporary object? If so, which link object can be attached? An object that can accept an address?

Thanks!

+5
c ++
source share
3 answers

0 is not an lvalue, it is the value of r. You cannot change it, but you are trying to bind a link where it can be changed.

If you make a const reference, it will work as expected. Consider this:

 int& x = 0; x = 1; // wtf :( 

This is obviously not-go. But const& can be attached to temporary (rvalues):

 const int& x = 0; x = 1; // protected :) [won't compile] 

Note that the temporary completion lifetime expires upon completion of the constructor. If you make static storage for your constant, you will be safe:

 class Foo { public: static const int Zero = 0; Foo() : x(Zero) // Zero has storage { y = 1; } private: const int& x; int y; }; 
+15
source share

A durable link must be bound to an lvalue . In principle, as you so eloquently put it, an object having a specific address. If they are tied to a temporary, the temporary will be destroyed while the link still refers to it, and the results are undefined.

Short-lived const links (local function variables and function arguments) can be tied to temporary ones. If they are, a temporary one is guaranteed that it will not be destroyed until the link goes beyond.

Demo Code:

 #include <iostream> class Big { public: Big() : living_(true), i_(5) { // This initialization of i is strictly legal but void *me = this; // the result is undefined. ::std::cerr << "Big constructor called for " << me << "\n"; } ~Big() { void *me = this; living_ = false; ::std::cerr << "Big destructor called for " << me << "\n"; } bool isLiving() const { return living_; } const int &getIref() const; const int *getIptr() const; private: ::std::string s_; bool living_; const int &i_; char stuff[50]; }; const int &Big::getIref() const { return i_; } const int *Big::getIptr() const { return &i_; } inline ::std::ostream &operator <<(::std::ostream &os, const Big &b) { const void *thisb = &b; return os << "A " << (b.isLiving() ? "living" : "dead (you're lucky this didn't segfault or worse)") << " Big at " << thisb << " && b.getIref() == " << b.getIref() << " && *b.getIptr() == " << *b.getIptr(); } class A { public: A() : big_(Big()) {} const Big &getBig() const { return big_; } private: const Big &big_; }; int main(int argc, char *argv[]) { A a; const Big &b = Big(); const int &i = 0; ::std::cerr << "a.getBig() == " << a.getBig() << "\n"; ::std::cerr << "b == " << b << "\n"; ::std::cerr << "i == " << i << "\n"; return 0; } 

And the conclusion:

 Big constructor called for 0x7fffebaae420 Big destructor called for 0x7fffebaae420 Big constructor called for 0x7fffebaae4a0 a.getBig() == A living Big at 0x7fffebaae420 && b.getIref() == -341121936 && *b.getIptr() == -341121936 b == A living Big at 0x7fffebaae4a0 && b.getIref() == 0 && *b.getIptr() == 0 i == 0 Big destructor called for 0x7fffebaae4a0 
0
source share

Well, you can never change it, 0 can never be equal to anything other than 0.

to try

  class Foo { public: Foo(int& a):x(a) { y = 1; } private: int& x; int y; }; 

Alternatively, you can do this if your link is permanent, because then 0 can only be zero

0
source share

All Articles