References again

J

JKop

Take the following:

int GiveMeInt(void)
{
return 734;
}


int main(void)
{
const int& plain = GiveMeInt();

//Time goes by

TakeConstIntPointer(&plain);
}


I know that there's nothing wrong with the above because the reference has
extended the life of the variable.


But take the following:


int& GiveMeIntRef(void)
{
int cow = 343;

return cow;
}


int main(void)
{
const int& ref = GiveMeIntRef();

//Time goes by

TakeConstIntPointer(&ref);
}


Has the lifetime been extended in the above?? Or am I accessing a variable
that no longer exists? If so, should I take the following as a general
guidline: Only return a reference from a function if it was declared via
new. ?


-JKop
 
R

Rob Williscroft

JKop wrote in in comp.lang.c++:
Take the following:
[yummie]

I know that there's nothing wrong with the above because the reference
has extended the life of the variable.


But take the following:


int& GiveMeIntRef(void)
{
int cow = 343;

UB - starts here.
return cow;
}


int main(void)
{
const int& ref = GiveMeIntRef();

ref here is bound to a *reference* that referes to a value that
nolonger exists.
//Time goes by

TakeConstIntPointer(&ref);
}


Has the lifetime been extended in the above??

No, only the lifetime of temporaries can be extended, GiveMeIntRef()
returns a reference, there is no temporary invloved.
Or am I accessing a
variable that no longer exists?
Yes.

If so, should I take the following as
a general guidline: Only return a reference from a function if it was
declared via new. ?

No, only return refrence to things that *aren't* going to be
destroyed before the caller has finnished with them.

int global = 0;

struct X
{
int x;
int &ref( bool b )
{
if ( b ) return x;
return global;
}
};

Rob.
 
J

JKop

OK. I understand references. From *my* understanding, here's my tutorial:


#include <iostream>

int main(void)
{
int a = 72;

int &b = a;

if ( (a!=b) || (&a != &b) )
{
std::cout << "Burn this compiler";
}
}


Then there's function arguments:


#include <iostream>

void Sugar(int& sweet)
{
sweet += 7;
}


int main(void)
{
int salt = 14;

Sugar(salt);

if(salt != 21)
{
std::cout << "Burn this compiler";
}
}



...then there's return values:


#include <iostream>

int& MintGood(void)
{
static int cheese = 7;

return cheese;
}

int& MintBad(void)
{
int cheese = 7;

return cheese;
}

int main(void)
{
const int& chalk_good = MintGood();

const int& chalk_bad = MintBad();


TakesConstIntPointer(&chalk_good); //Fine and dandy

TakesConstIntPointer(&chalk_bad); //Undefined behaviour
}



And then...


int sheep(void)
{
return 72;
}


int main(void)
{
const int& purple = sheep();

TakesConstIntPointer(&purple); //This is, I repeat, is, valid.
//The lifetime of the temporary
//has been extended!
}



And finally:


struct Poo
{
int& account_number;
int& monkey_age;
};



Think of the above as

struct Poo
{
int* const account_number;
int* const monkey_age;
};



And that, I believe, is references in a nutshell!


-JKop
 
I

Ioannis Vranos

JKop said:
Take the following:

int GiveMeInt(void)
{
return 734;
}


int main(void)
{
const int& plain = GiveMeInt();


Here a temporary is returned by GiveMeInt and 734 is lost. All these in
theory of course, a decent compiler can inline the above.


But take the following:


int& GiveMeIntRef(void)
{
int cow = 343;

return cow;
}


int main(void)
{
const int& ref = GiveMeIntRef();


Here a reference to a dead object is returned.


//Time goes by

TakeConstIntPointer(&ref);
}


Has the lifetime been extended in the above?? Or am I accessing a variable
that no longer exists? If so, should I take the following as a general
guidline: Only return a reference from a function if it was declared via
new. ?


Yes if the object is on the free store or is of static linkage (e.g. a
global, or a static local variable).






Regards,

Ioannis Vranos
 
I

Ioannis Vranos

JKop said:
OK. I understand references. From *my* understanding, here's my tutorial:


#include <iostream>

int main(void)
{
int a = 72;

int &b = a;

if ( (a!=b) || (&a != &b) )
{
std::cout << "Burn this compiler";
}
}

Correct.




Then there's function arguments:


#include <iostream>

void Sugar(int& sweet)
{
sweet += 7;
}


int main(void)
{
int salt = 14;

Sugar(salt);

if(salt != 21)
{
std::cout << "Burn this compiler";
}
}

Correct.



...then there's return values:


#include <iostream>

int& MintGood(void)
{
static int cheese = 7;

return cheese;
}

int& MintBad(void)
{
int cheese = 7;

return cheese;
}

int main(void)
{
const int& chalk_good = MintGood();

const int& chalk_bad = MintBad();


TakesConstIntPointer(&chalk_good); //Fine and dandy

TakesConstIntPointer(&chalk_bad); //Undefined behaviour
}


Correct.



And then...


int sheep(void)
{
return 72;
}


int main(void)
{
const int& purple = sheep();

TakesConstIntPointer(&purple); //This is, I repeat, is, valid.
//The lifetime of the temporary
//has been extended!
}



Yes but only as far as the object referenced by purple is not used after
purple ceases to exist (along with its temporary at the end of purple
scope).


So for example if

// Disastrous
void TakesConstIntPointer(const int *p)
{
// Disaster is going to happen

//Or stores it in a global, namespace or whatever else of static
// linkage
static const int *somep=p;

// ...

}





And finally:


struct Poo
{
int& account_number;
int& monkey_age;
};



Think of the above as

struct Poo
{
int* const account_number;
int* const monkey_age;
};



And that, I believe, is references in a nutshell!


Yes only that references do not have an address of their own and you
cannot assume that they occupy space.


Some quotes of the "C++ Programming Language" 3rd Edition or Special
Edition by Bjarne Stroustrup (the creator of C++):


"Initialization of a reference is something quite different from
assignment to it. Despite appearances, no operator operates on a
reference. For example:


void g()
{
int ii = 0;
int& rr = ii;
rr++; / / ii is incremented to 1
int* pp= &rr; / / pp points to ii
}

This is legal, but rr++ does not increment the reference rr; rather, ++
is applied to an int that happens to be ii. Consequently, the value of a
reference cannot be changed after initialization; it always refers to
the object it was initialized to denote. To get a pointer to the object
denoted by a reference rr, we can write &rr.
The obvious implementation of a reference is as a (constant) pointer
that is dereferenced each time it is used. It doesn’t do much harm
thinking about references that way, as long as one remembers that a
reference isn’t an object that can be manipulated the way a pointer is:



[There's a drawing here]



In some cases, the compiler can optimize away a reference so that there
is no object representing that reference at runtime."






Regards,

Ioannis Vranos
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,171
Messages
2,570,935
Members
47,472
Latest member
KarissaBor

Latest Threads

Top