Re: Returning a reference to a local variable
On Dec 30, 12:31 am, pauldepst...@att.net wrote:
On Dec 30, 1:00 pm, Salt_Peter <pj_h...@yahoo.com> wrote:
On Dec 29, 10:40 pm, pauldepst...@att.net wrote:
#include <iostream>
using namespace std;
double & GetWeeklyHours()
{
double h = 46.50;
double &hours = h;
return hours;}
//--------------------------------------------------------------------=
-----=AD--
int main()
{
double hours = GetWeeklyHours();
cout << "Weekly Hours: " << hours << endl;
return 0;
}
According to a (hopefully reliable) website, the above is correct
code.
Why is the above _not_ an example of the sin of "returning a reference=
to a local variable"? What is the difference between the return-
reference-to-local problem and the above code?
It is an example of undefined behaviour. A compiler is not required to
generate a diagnostic either.
Is it accepteable? Not in a long shot.
Here, try the following and pay attention to the output and sequence
of events.
#include <iostream>
class Hours
{
double m_d;
public:
Hours() : m_d(0.0) { std::cout << "Hours()\n"; }
Hours(double d) : m_d(d) { std::cout << "Hours(double)\n"; }
~Hours() { std::cout << "~Hours()\n"; }
Hours(const Hours& copy)
{
std::cout << "Hours(const Hours& copy)\n";
m_d = copy.m_d;
}
double get() const { return m_d; }
};
Hours& GetWeeklyHours()
{
Hours h = 46.50;
std::cout << "local initialized\n";
Hours& hours = h;
std::cout << "reference set\n";
return hours;
}
//----------------------------------------------------------------------=
---=AD--
int main()
{
Hours hours = GetWeeklyHours(); // is a copy (1)
std::cout << "Weekly Hours: " << hours.get() << std::endl;
}
/*
Hours(double)
local initialized
reference set
~Hours() // local destroyed here
Hours(const Hours& copy) // is a copy (1) of a reference
Weekly Hours: 6.95329e-310
~Hours()
*/
The basic rule of thumb is: if a local invokes a default or
parametized ctor, not a copy, it only lives in that scope.
It doesn't matter whether you use a reference, a 'reference to const'
or a 'pointer to const', the residual garbage left over from the
destruction of the local variable can't be guarenteed. Anything can
happen.
this is fine, btw:
Hours GetWeeklyHours()
{
return Hours(46.5);
}
but this is not:
Hours const& GetWeeklyHours()
{
return Hours(46.5);
}- Hide quoted text -
- Show quoted text -- Hide quoted text -
- Show quoted text -
Thanks, Peter. You seem to have put a lot of time and effort towards
helping me and I appreciate that. However, I'm still a bit confused.
I understand why your example code is bugged. The mystery (to me) is
why the code I posted originally _does not_ appear to suffer from the
reference-to-local bug. It works on my compiler, and was copied from
what seemed like a decent website. Are you saying that my original
code suffers from the same bug but that sometimes the local is
destroyed at a late enough time so that the original code still gives
correct results? My question is: Why does the original code give
reliable results even though it appears to return a reference to a
local?
Paul Epstein
First off - you may very well find others to have a different point of
view than mine.
You might even find a compiler with some scheme that makes the above
work with primitives (stored in a register? who knows - i really don't
care).
The fact remains, once the scope ends:
a) the local variable is no more
b) that area of memory is therefore left unprotected (its writeable)
So if you have a busy program (multi-threaded, etc)... its only a
question of time.
Debugging an issue that only happens intermittently is near
impossible. Testing for UB is easy comparatively.
A completely different Issue...
The standard specifically says you can't bind a 'reference to non-
const' to a temporary. Many beleive this means that its ok to *return*
a local through a reference to const. Well, not quite. The standard,
as i understand it, says this:
void DisplayHours(const double& ref) // must be a ref to const
{
std::cout << ref << std::endl;
}
int main()
{
DisplayHours(double(99));
}
The above works because double(99), a temporary, has a lifetime that
lasts until the function ceases to exist.
That, by the way, is the better way to write your GetWeeklyHours
function, pass the variable by reference_to_const which safely
modifies the original. At least thats guarenteed 100% of the time.
Hopefully, a little light was thrown on this and if not, someone else
can give it a go.