Returning a reference to a local variable

Discussion in 'C++' started by pauldepstein@att.net, Dec 30, 2007.

  1. Guest

    #include <iostream>
    using namespace std;

    double & GetWeeklyHours()
    {
    double h = 46.50;
    double &hours = h;
    return hours;
    }
    //---------------------------------------------------------------------------
    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?

    Thanks,

    Paul Epstein
    , Dec 30, 2007
    #1
    1. Advertising

  2. Salt_Peter Guest

    On Dec 29, 10:40 pm, wrote:
    > #include <iostream>
    > using namespace std;
    >
    > double & GetWeeklyHours()
    > {
    > double h = 46.50;
    > double &hours = h;
    > return hours;}
    >
    > //---------------------------------------------------------------------------
    > 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;
    }

    //---------------------------------------------------------------------------
    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);
    }
    Salt_Peter, Dec 30, 2007
    #2
    1. Advertising

  3. Guest

    On Dec 30, 1:00 pm, Salt_Peter <> wrote:
    > On Dec 29, 10:40 pm, wrote:
    >
    >
    >
    >
    >
    > > #include <iostream>
    > > using namespace std;

    >
    > > double & GetWeeklyHours()
    > > {
    > >     double h = 46.50;
    > >     double &hours = h;
    > >     return hours;}

    >
    > > //-------------------------------------------------------------------------­--
    > > 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;
    >
    > }
    >
    > //-------------------------------------------------------------------------­--
    > 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
    , Dec 30, 2007
    #3
  4. Kira Yamato Guest

    On 2007-12-29 22:40:31 -0500, said:

    > #include <iostream>
    > using namespace std;
    >
    > double & GetWeeklyHours()
    > {
    > double h = 46.50;
    > double &hours = h;
    > return hours;
    > }
    > //---------------------------------------------------------------------------
    > int main()
    > {
    > double hours = GetWeeklyHours();
    >
    > cout << "Weekly Hours: " << hours << endl;
    >
    > return 0;
    > }
    >
    >
    > According to a (hopefully reliable) website, the above is correct
    > code.


    No. As far as I know, the standard makes no guarantee a behavior for
    this code. This is no correct code.

    BTW, please give the link to that website.

    --

    -kira
    Kira Yamato, Dec 30, 2007
    #4
  5. Guest

    On Dec 30, 1:31 pm, Kira Yamato <> wrote:
    > On 2007-12-29 22:40:31 -0500, said:
    >
    >
    >
    >
    >
    > > #include <iostream>
    > > using namespace std;

    >
    > > double & GetWeeklyHours()
    > > {
    > >     double h = 46.50;
    > >     double &hours = h;
    > >     return hours;
    > > }
    > > //-------------------------------------------------------------------------­--
    > > int main()
    > > {
    > >     double hours = GetWeeklyHours();

    >
    > >     cout << "Weekly Hours: " << hours << endl;

    >
    > >     return 0;
    > > }

    >
    > > According to a (hopefully reliable) website, the above is correct
    > > code.

    >
    > No.  As far as I know, the standard makes no guarantee a behavior for
    > this code.  This is no correct code.
    >
    > BTW, please give the link to that website.
    >
    > --
    >
    > -kira- Hide quoted text -
    >
    > - Show quoted text -


    Thanks Kira and Peter

    The link is http://www.functionx.com/cpp/examples/returnreference.htm
    The reason I was reluctant to include the link at the beginning is
    that I didn't want to be seen as unfairly accusing the people who
    designed the website.

    Paul Epstein
    , Dec 30, 2007
    #5
  6. Salt_Peter Guest

    On Dec 30, 12:31 am, wrote:
    > On Dec 30, 1:00 pm, Salt_Peter <> wrote:
    >
    >
    >
    > > On Dec 29, 10:40 pm, wrote:

    >
    > > > #include <iostream>
    > > > using namespace std;

    >
    > > > double & GetWeeklyHours()
    > > > {
    > > > double h = 46.50;
    > > > double &hours = h;
    > > > return hours;}

    >
    > > > //-------------------------------------------------------------------------­--
    > > > 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;

    >
    > > }

    >
    > > //-------------------------------------------------------------------------­--
    > > 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.
    Salt_Peter, Dec 30, 2007
    #6
  7. Dreamlax Guest

    > 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.
    >
    > Paul Epstein


    I think on most systems, when a program is compiled, its size reflects
    the number of local variables declared in the code. For example, if a
    long integer required 4 bytes, then the program's compiled code will
    increase by 4 bytes for every long integer (and then rounded to the
    nearest 16k block or whatever). This is because the entire program is
    loaded into memory at once. After it is loaded into memory, local (and
    global) variables now become addressable places in memory. If the
    compiler is very smart, and knows that the code is not multithreaded,
    it may use the same 4 bytes as the local integer variable in two
    separate functions just to save on filesize. Therefore, the reference
    returned by one function may point to a place in memory that can be
    changed through another local variable in another function. The
    contents of the memory addressed by the return value of that function
    cannot be guaranteed to be constant throughout the remainder of the
    execution of the program.
    Dreamlax, Dec 30, 2007
    #7
  8. On 2007-12-30 09:43, Dreamlax wrote:
    >> 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.
    >>
    >> Paul Epstein

    >
    > I think on most systems, when a program is compiled, its size reflects
    > the number of local variables declared in the code. For example, if a
    > long integer required 4 bytes, then the program's compiled code will
    > increase by 4 bytes for every long integer (and then rounded to the
    > nearest 16k block or whatever). This is because the entire program is
    > loaded into memory at once. After it is loaded into memory, local (and
    > global) variables now become addressable places in memory. If the
    > compiler is very smart, and knows that the code is not multithreaded,
    > it may use the same 4 bytes as the local integer variable in two
    > separate functions just to save on filesize. Therefore, the reference
    > returned by one function may point to a place in memory that can be
    > changed through another local variable in another function. The
    > contents of the memory addressed by the return value of that function
    > cannot be guaranteed to be constant throughout the remainder of the
    > execution of the program.


    No. Local variables are (usually, I sure there exists exceptions) placed
    on the stack, which is allocated on runtime. When a function is called a
    new stackframe, which is big enough to contain all local variables of
    the function, is pushed onto the stack. When the function exits the
    frame is poped of the stack. But the memory used is left as it was, this
    means that as long as no new frame is pushed onto the stack and over-
    writes the memory the values will still be readable. This does not mean
    that one should try to be smart and try to "utilise" this, it will only
    lead to ruin.

    --
    Erik Wikström
    Erik Wikström, Dec 30, 2007
    #8
  9. Daniel T. Guest

    wrote:

    > #include <iostream>
    > using namespace std;
    >
    > double & GetWeeklyHours()
    > {
    > double h = 46.50;
    > double &hours = h;
    > return hours;
    > }
    > //---------------------------------------------------------------------------
    > 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?


    As I understand it, the example code works because RVO constructs the
    local variable at the site of main's 'hours' variable.

    Without RVO, the above code would not work, and RVO cannot be guaranteed.
    Daniel T., Dec 30, 2007
    #9
  10. Ron Natalie Guest

    Daniel T. wrote:

    >
    > As I understand it, the example code works because RVO constructs the
    > local variable at the site of main's 'hours' variable.
    >
    > Without RVO, the above code would not work, and RVO cannot be guaranteed.


    Well more likely, the RVO just causes the copy to the main:hours
    variable before the GetWeeklyHours:h is obliterated.

    One of those insidious forms of undefined behavior is things appear to
    work normally, TODAY.
    Ron Natalie, Dec 30, 2007
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alexander Stippler
    Replies:
    2
    Views:
    624
    Alexander Stippler
    Jul 4, 2003
  2. Kench
    Replies:
    2
    Views:
    5,408
    Victor Bazarov
    Jun 28, 2004
  3. Alex6996xelA
    Replies:
    0
    Views:
    273
    Alex6996xelA
    Apr 15, 2005
  4. Alex6996xelA
    Replies:
    3
    Views:
    350
    codigo
    Apr 15, 2005
  5. Spitfire

    returning address of a local variable

    Spitfire, Nov 23, 2006, in forum: C Programming
    Replies:
    14
    Views:
    482
    Peter Shaggy Haywood
    Nov 26, 2006
Loading...

Share This Page