Returning a reference to a local variable

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • pauldepstein@att.net

    #1

    Returning a reference to a local variable

    #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
  • Salt_Peter

    #2
    Re: Returning a reference to a local variable

    On Dec 29, 10:40 pm, pauldepst...@at t.net 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(cons t 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);
    }



    Comment

    • pauldepstein@att.net

      #3
      Re: Returning a reference to a local variable

      On Dec 30, 1:00 pm, Salt_Peter <pj_h...@yahoo. comwrote:
      On Dec 29, 10:40 pm, pauldepst...@at t.net 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(cons t 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

      Comment

      • Kira Yamato

        #4
        Re: Returning a reference to a local variable

        On 2007-12-29 22:40:31 -0500, pauldepstein@at t.net 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

        Comment

        • pauldepstein@att.net

          #5
          Re: Returning a reference to a local variable

          On Dec 30, 1:31 pm, Kira Yamato <kira...@earthl ink.netwrote:
          On 2007-12-29 22:40:31 -0500, pauldepst...@at t.net 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/example...nreference.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

          Comment

          • Salt_Peter

            #6
            Re: Returning a reference to a local variable

            On Dec 30, 12:31 am, pauldepst...@at t.net wrote:
            On Dec 30, 1:00 pm, Salt_Peter <pj_h...@yahoo. comwrote:
            >
            >
            >
            On Dec 29, 10:40 pm, pauldepst...@at t.net 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(cons t 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(co nst double& ref) // must be a ref to const
            {
            std::cout << ref << std::endl;
            }

            int main()
            {
            DisplayHours(do uble(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_co nst 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.

            Comment

            • Daniel T.

              #7
              Re: Returning a reference to a local variable

              pauldepstein@at t.net 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.

              Comment

              • Ron Natalie

                #8
                Re: Returning a reference to a local variable

                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.

                Comment

                Working...