I was told the reference variable must be initialized in the initialization list, but why this is wrong?
class Foo
{
public:
开发者_高级运维 Foo():x(0) {
y = 1;
}
private:
int& x;
int y;
};
Because 0 is a temporary object? If so, what kind of object can reference be bound? The object which can take an address?
Thanks!
0 is not an lvalue, it's an rvalue. You cannot modify it, but you're trying to bind to a reference where it could be modified.
If you make your reference const
, it will work as expected. Consider this:
int& x = 0;
x = 1; // wtf :(
This obviously is a no-go. But const&
's can be bound to temporaries (rvalues):
const int& x = 0;
x = 1; // protected :) [won't compile]
Note that the life-time of the temporary is ended at the completion of the constructor. If you make static-storage for your constant, you'll be safe:
class Foo
{
public:
static const int Zero = 0;
Foo() : x(Zero) // Zero has storage
{
y = 1;
}
private:
const int& x;
int y;
};
Well, you can never change it, 0 can never equal anything other than 0.
try
class Foo
{
public:
Foo(int& a):x(a) {
y = 1;
}
private:
int& x;
int y;
};
Alternatively, you can do this if your reference is constant because then 0 can only ever equal zero
A long lived reference must be bound to an lvalue
. Basically, as you so eloquently put it, an object that has a definite address. If they are bound to a temporary the temporary will be destroyed while the reference is still referencing it and the results are undefined.
Short lived const references (local function variables and function arguments) can be bound to temporaries. If they are, the temporary is guaranteed to not be destroyed until the reference goes out of scope.
Demonstration 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 output:
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
精彩评论