How Methods Return Objects

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • cppaddict

    How Methods Return Objects

    I'd like to know what goes on under the hood when methods return
    objects. Eg, I have a simple Point class with two members _x and _y.
    It's constructor, copy constructor, assignment operator and additon
    operator (which returns another Point object, and which my question is
    about) are as follows:

    Point::Point(in t x, int y) :
    _x(x),
    _y(y) { }

    Point::Point(co nst Point& p) {
    _x = p._x;
    _y = p._y;
    }

    Point& Point::operator =(const Point& p) {
    _x = p._x;
    _y = p._y;
    return (*this);
    }

    Point Point::operator +(const Point& p) const {
    Point ret(_x + p._x, _y + p._y);
    return ret;
    }

    What happens when operator+ returns the temporary Point object that it
    creates?

    Does it use the copy constructor to create a copy of the temporary
    variable "ret"? Is ret destroyed after that?

    If not, how does it return a Point object?

    Also, why is that "new" never comes into play? How can the compiler
    know beforehand how many Point objects will be created via operator+?
    Is it because such objects must exist in statements like:

    Point p3 = p1 + p2;

    I know this is a simple point, but I'm confused nonetheless.

    Thanks for any clarification,
    cpp

  • Victor Bazarov

    #2
    Re: How Methods Return Objects

    "cppaddict" <hello@hello.co m> wrote...[color=blue]
    > I'd like to know what goes on under the hood when methods return
    > objects. Eg, I have a simple Point class with two members _x and _y.
    > It's constructor, copy constructor, assignment operator and additon
    > operator (which returns another Point object, and which my question is
    > about) are as follows:
    >
    > Point::Point(in t x, int y) :
    > _x(x),
    > _y(y) { }
    >
    > Point::Point(co nst Point& p) {
    > _x = p._x;
    > _y = p._y;[/color]

    I wonder why you didn't use initialisation here...
    [color=blue]
    > }
    >
    > Point& Point::operator =(const Point& p) {
    > _x = p._x;
    > _y = p._y;
    > return (*this);
    > }
    >
    > Point Point::operator +(const Point& p) const {
    > Point ret(_x + p._x, _y + p._y);
    > return ret;
    > }
    >
    > What happens when operator+ returns the temporary Point object that it
    > creates?
    >
    > Does it use the copy constructor to create a copy of the temporary
    > variable "ret"? Is ret destroyed after that?[/color]

    Generally speaking, yes. Since 'ret' is an automatic variable, it will
    be destroyed right after the function ends (right after the 'return'
    statement). In order for the Point object to exist after the function
    has finished but before its value is used elsewhere, a temporary one
    is created using the copy constructor.
    [color=blue]
    >
    > If not, how does it return a Point object?
    >
    > Also, why is that "new" never comes into play?[/color]

    How do you know it doesn't? Creation of a temporary _might_ be internally
    done using some kind of special form of 'new'. It's not defined, AFAIK.
    Where the temporary is created and how is, well, unimportant. At least
    from the langauge standpoint.
    [color=blue]
    > How can the compiler
    > know beforehand how many Point objects will be created via operator+?[/color]

    Every time it has to call operator+ function, another Point object is
    potentially created.
    [color=blue]
    > Is it because such objects must exist in statements like:
    >
    > Point p3 = p1 + p2;[/color]

    The compiler is allowed to forgo creation of a temporary in this case
    and instead generate code so that when you return the 'ret' from the
    function operator+, it is used to directly initialise the 'p3' object.

    You might find all that in good books. Or by looking at the code (yes,
    it's usually assembly language) that the compiler generates from your
    C++ source.

    Victor


    Comment

    • cppaddict

      #3
      Re: How Methods Return Objects

      [color=blue][color=green]
      >> Point::Point(co nst Point& p) {
      >> _x = p._x;
      >> _y = p._y;[/color]
      >
      >I wonder why you didn't use initialisation here...[/color]

      I should have. Thanks for pointing that out.

      Thanks for you other explanations as well.

      cpp

      Comment

      • Mark A. Gibbs

        #4
        Re: How Methods Return Objects


        cppaddict wrote:
        [color=blue][color=green][color=darkred]
        >>>Point::Point (const Point& p) {
        >>>_x = p._x;
        >>>_y = p._y;[/color][/color][/color]

        it is unwise to use a leading underscore in a variable name, although in
        this case, not technically illegal (17.4.3.1.2).

        mark

        Comment

        • cppaddict

          #5
          Re: How Methods Return Objects

          >it is unwise to use a leading underscore in a variable name, although in[color=blue]
          >this case, not technically illegal (17.4.3.1.2).
          >
          >mark[/color]

          I was under the (mistaken) impression that this was a standard way to
          indicate member variables. Do you know what leading underscores are
          reserved for? Also, what is the standard way to indicate a member
          variable -- trailing underscore?

          Thanks,
          cpp

          Comment

          • Victor Bazarov

            #6
            Re: How Methods Return Objects

            "cppaddict" <hello@hello.co m> wrote...[color=blue][color=green]
            > >it is unwise to use a leading underscore in a variable name, although in
            > >this case, not technically illegal (17.4.3.1.2).
            > >
            > >mark[/color]
            >
            > I was under the (mistaken) impression that this was a standard way to
            > indicate member variables. Do you know what leading underscores are
            > reserved for? Also, what is the standard way to indicate a member
            > variable -- trailing underscore?[/color]

            There is no "standard way" to indicate anything. The Standard prohibits
            the use of reserved [by the implementation] names. Such names include
            names with double underscores and names that begin with an underscore and
            a capital letter.

            I am, of course, picking at your use of the word "standard" here. Not
            that I have ill will, but traditionally "standard" here means required
            or defined by the Standard Document. You might want to use the word
            "convention al", as in "what is the conventional way to indicate..."

            As to the accepted conventions, there are several. The one I see used
            the most is the prefix 'm_' for non-static data members and 's_' for
            static data members. Leading underscores, just like trailing underscores,
            are not easy to read, that's why most people try to avoid them, I guess.

            Victor


            Comment

            • John Harrison

              #7
              Re: How Methods Return Objects

              On Fri, 30 Jul 2004 03:18:57 GMT, cppaddict <hello@hello.co m> wrote:
              [color=blue][color=green]
              >> it is unwise to use a leading underscore in a variable name, although in
              >> this case, not technically illegal (17.4.3.1.2).
              >>
              >> mark[/color]
              >
              > I was under the (mistaken) impression that this was a standard way to
              > indicate member variables. Do you know what leading underscores are
              > reserved for? Also, what is the standard way to indicate a member
              > variable -- trailing underscore?
              >
              > Thanks,
              > cpp
              >[/color]

              Its a good way to indicate member variables. I don't understand why some
              people claim its dangerous (I am aware of when underscore use is illegal).
              Perhaps Mark could justify his claim?

              john


              Comment

              • Denis Remezov

                #8
                Re: How Methods Return Objects

                John Harrison wrote:[color=blue]
                >
                > On Fri, 30 Jul 2004 03:18:57 GMT, cppaddict <hello@hello.co m> wrote:
                >[color=green][color=darkred]
                > >> it is unwise to use a leading underscore in a variable name, although in
                > >> this case, not technically illegal (17.4.3.1.2).
                > >>
                > >> mark[/color]
                > >
                > > I was under the (mistaken) impression that this was a standard way to
                > > indicate member variables. Do you know what leading underscores are
                > > reserved for? Also, what is the standard way to indicate a member
                > > variable -- trailing underscore?
                > >
                > > Thanks,
                > > cpp
                > >[/color]
                >
                > Its a good way to indicate member variables. I don't understand why some
                > people claim its dangerous (I am aware of when underscore use is illegal).
                > Perhaps Mark could justify his claim?
                >
                > john[/color]

                Some say that it's hard to remember the exact rules (never use a leading
                underscore followed by an uppercase letter; never use a double underscore;
                in the global scope, don't use a leading underscore regardless of the
                symbol that follows). There is some potential for an error here,
                especially due to code maintenance by those who don't read too much
                into language details.
                This potential is arguably smaller when using a trailing underscore
                instead.

                I don't mind it either way (and much prefer them over any alternative),
                but in my limited scope the trailing underscore has become more
                conventional. I've got used to it and love it.

                Denis

                Comment

                • John Harrison

                  #9
                  Re: How Methods Return Objects


                  "Denis Remezov" <firstname_surn ame@yahoo.remov ethis.ca> wrote in message
                  news:4109C44B.F 3947597@yahoo.r emovethis.ca...[color=blue]
                  > John Harrison wrote:[color=green]
                  > >
                  > > On Fri, 30 Jul 2004 03:18:57 GMT, cppaddict <hello@hello.co m> wrote:
                  > >[color=darkred]
                  > > >> it is unwise to use a leading underscore in a variable name, although[/color][/color][/color]
                  in[color=blue][color=green][color=darkred]
                  > > >> this case, not technically illegal (17.4.3.1.2).
                  > > >>
                  > > >> mark
                  > > >
                  > > > I was under the (mistaken) impression that this was a standard way to
                  > > > indicate member variables. Do you know what leading underscores are
                  > > > reserved for? Also, what is the standard way to indicate a member
                  > > > variable -- trailing underscore?
                  > > >
                  > > > Thanks,
                  > > > cpp
                  > > >[/color]
                  > >
                  > > Its a good way to indicate member variables. I don't understand why some
                  > > people claim its dangerous (I am aware of when underscore use is[/color][/color]
                  illegal).[color=blue][color=green]
                  > > Perhaps Mark could justify his claim?
                  > >
                  > > john[/color]
                  >
                  > Some say that it's hard to remember the exact rules (never use a leading
                  > underscore followed by an uppercase letter; never use a double underscore;
                  > in the global scope, don't use a leading underscore regardless of the
                  > symbol that follows). There is some potential for an error here,
                  > especially due to code maintenance by those who don't read too much
                  > into language details.
                  > This potential is arguably smaller when using a trailing underscore
                  > instead.
                  >
                  > I don't mind it either way (and much prefer them over any alternative),
                  > but in my limited scope the trailing underscore has become more
                  > conventional. I've got used to it and love it.
                  >
                  > Denis[/color]

                  I guess I prefer a leading underscore because its the first thing you see
                  when you read a name. I guess the same reason you often see m_something but
                  never something_m.

                  But yes, beauty is in the eye of the beholder.

                  john


                  Comment

                  • Sharad Kala

                    #10
                    Re: How Methods Return Objects


                    "John Harrison" <john_andronicu s@hotmail.com> wrote in message
                    news:opsbxo1yjt 212331@andronic us...[color=blue]
                    > On Fri, 30 Jul 2004 03:18:57 GMT, cppaddict <hello@hello.co m> wrote:
                    >[/color]
                    [color=blue]
                    > Its a good way to indicate member variables. I don't understand why some
                    > people claim its dangerous (I am aware of when underscore use is illegal).
                    > Perhaps Mark could justify his claim?[/color]

                    Because they are used by the compiler implementations too.
                    To quote Herb Sutter here - "Try to avoid names with leading underscores.
                    Yes, I've habitually used them, and yes, popular books like "Design
                    Patterns" (Gamma et al) do use it... but the standard reserves some
                    leading-underscore identifiers for the implementation and the rules are hard
                    enough to remember (for you and for compiler writers!) that you might as
                    well avoid this in new code. (Since I'm no longer allowed to use leading
                    underscores as my "member variable" tag, I'll now use trailing
                    underscores!)"

                    This simple program on MS VC 7.0 cribs for ambiguous symbol -

                    #include <map>
                    using namespace std;
                    class _Tree{
                    };

                    int main()
                    {
                    _Tree t;
                    }

                    -Sharad



                    Comment

                    • John Harrison

                      #11
                      Re: How Methods Return Objects


                      "Sharad Kala" <no__spam.shara dk_ind@yahoo.co m> wrote in message
                      news:2mui3iFr05 t4U1@uni-berlin.de...[color=blue]
                      >
                      > "John Harrison" <john_andronicu s@hotmail.com> wrote in message
                      > news:opsbxo1yjt 212331@andronic us...[color=green]
                      > > On Fri, 30 Jul 2004 03:18:57 GMT, cppaddict <hello@hello.co m> wrote:
                      > >[/color]
                      >[color=green]
                      > > Its a good way to indicate member variables. I don't understand why some
                      > > people claim its dangerous (I am aware of when underscore use is[/color][/color]
                      illegal).[color=blue][color=green]
                      > > Perhaps Mark could justify his claim?[/color]
                      >
                      > Because they are used by the compiler implementations too.
                      > To quote Herb Sutter here - "Try to avoid names with leading underscores.
                      > Yes, I've habitually used them, and yes, popular books like "Design
                      > Patterns" (Gamma et al) do use it... but the standard reserves some
                      > leading-underscore identifiers for the implementation and the rules are[/color]
                      hard[color=blue]
                      > enough to remember (for you and for compiler writers!) that you might as
                      > well avoid this in new code. (Since I'm no longer allowed to use leading
                      > underscores as my "member variable" tag, I'll now use trailing
                      > underscores!)"[/color]

                      I don't find the rule, 'use a leading underscore followed by a lower case
                      letter for member variables' hard to remember. I would always use a leading
                      lower case letter in any case even if I wasn't using a leading underscore. I
                      don't think the argument that you 'might as well' avoid it in new code very
                      convincing. Why exactly? No bad things are going to happen that I can see.
                      [color=blue]
                      >
                      > This simple program on MS VC 7.0 cribs for ambiguous symbol -
                      >
                      > #include <map>
                      > using namespace std;
                      > class _Tree{
                      > };
                      >
                      > int main()
                      > {
                      > _Tree t;
                      > }
                      >
                      > -Sharad
                      >[/color]

                      That differs from what I would do in two different ways. First it is
                      underscore followed by an uppercase letter and second I am only talking
                      about member variable names.

                      john


                      Comment

                      • JKop

                        #12
                        Re: How Methods Return Objects

                        cppaddict posted:
                        [color=blue]
                        > I'd like to know what goes on under the hood when methods return
                        > objects. Eg, I have a simple Point class with two members _x and _y.
                        > It's constructor, copy constructor, assignment operator and additon
                        > operator (which returns another Point object, and which my question is
                        > about) are as follows:
                        >
                        > Point::Point(in t x, int y) :
                        > _x(x),
                        > _y(y) { }
                        >
                        > Point::Point(co nst Point& p) {
                        > _x = p._x;
                        > _y = p._y;
                        > }
                        >
                        > Point& Point::operator =(const Point& p) {
                        > _x = p._x;
                        > _y = p._y;
                        > return (*this);
                        > }
                        >
                        > Point Point::operator +(const Point& p) const {
                        > Point ret(_x + p._x, _y + p._y);
                        > return ret;
                        > }
                        >
                        > What happens when operator+ returns the temporary Point object that it
                        > creates?
                        >
                        > Does it use the copy constructor to create a copy of the temporary
                        > variable "ret"? Is ret destroyed after that?
                        >
                        > If not, how does it return a Point object?
                        >
                        > Also, why is that "new" never comes into play? How can the compiler
                        > know beforehand how many Point objects will be created via operator+?
                        > Is it because such objects must exist in statements like:
                        >
                        > Point p3 = p1 + p2;
                        >
                        > I know this is a simple point, but I'm confused nonetheless.
                        >
                        > Thanks for any clarification,
                        > cpp
                        >[/color]


                        int Blah()
                        {
                        return 72;
                        }

                        int main()
                        {
                        int f = 45 + Blah();
                        }


                        When the end of Blah is reached, a temporary is created and this temporary
                        is given back to main. The temporary lives in main up until the next
                        semicolon, at which point it's destroyed.

                        Now, here's one that may result in an optimization:

                        int Blah()
                        {
                        int f = 76;

                        f *= 2;

                        f -= 4;

                        return f;
                        }

                        The compiler may choose to return a temporary, which has been copy-
                        initialized from "f", or it may return "f" itself. If it returns "f" itself,
                        then there's one less object created, and that's the optimization.

                        And another optimization:

                        int Blah()
                        {
                        int f = 76;

                        f *= 2;

                        f -= 4;

                        return f;
                        }

                        int main()
                        {
                        int x = Blah();
                        }

                        That x variable in main may be used in Blah, as no temporary is necessary.


                        And then there's functions that return references...

                        int k; //global

                        int& Blah()
                        {
                        k = 6783;

                        k *= 2;

                        k -= 64;

                        return k;
                        }

                        Here Blah is returning a reference to a global variable, so the global
                        variable will still exist after the end of Blah, and so it can be used in
                        main().

                        If, on the other hand, you do this:

                        int& Blah()
                        {
                        int k = 72;

                        return k;
                        }

                        The Blah function will in fact return a reference to k, but by the time you
                        get to use it in main, k no longer exists. Compilers warn whenever you
                        return a reference to a local variable.


                        And then there's binding to a const-reference:

                        int Blah()
                        {
                        int k = 72;

                        k +=4;

                        k *= 2;

                        return k;
                        }

                        int main()
                        {
                        const int& monkey = Blah();

                        //Here, the temporary returned from Blah (or its local variable)
                        //is directly bound to monkey
                        //The temporary does NOT get destroyed at the
                        //next semicolon, but at the end of the reference's
                        //scope, ie. the end of main
                        }


                        You may ask why one would bother binding to a const reference when they can
                        just do:

                        int main()
                        {
                        int monkey = Blah();
                        }

                        and rely on the optimization.

                        Well, there needn't be an optimization depending on the compiler, and so
                        monkey may be copy-constructed from the temporary returned by Blah(). Plus,
                        if Blah returns a const object, then "int monkey" won't optimize, because a
                        copy will have to be made to yield a non-const version. On the other hand
                        you could do "const int monkey".

                        Well anyway, take this code:

                        int Blah()
                        {
                        int k = 42;

                        k *= 2;

                        k += 4;

                        return k;
                        }

                        int main()
                        {
                        int monkey = Blah();
                        }


                        How many "int"s are made? Either 1, 2 or 3. The best compilers will only use
                        one int, the monkey from main. The monkey will be used in Blah, and then
                        when Blah finishes, a temporary *won't* be made, it'll just return its local
                        variable, which is monkey from main!

                        Another compiler may make 2 "int"s: the monkey in main, and the k in Blah.
                        The Blah function will return k directly.

                        And then ofcourse there's compilers that'll make 3 "int"s:

                        The monkey from main
                        k from Blah
                        The temporary returned from Blah

                        There's times when a function has no choice but to create a temporary to
                        return, eg.

                        int Blah()
                        {
                        int k = 7;

                        return k + 4;
                        }

                        But if you return the variable directly, and there's no constness problems,
                        then there's no problems with the actual local variable being returned.

                        All of these are just optimizations, and needn't be performed.

                        (Another even better compiler may turn the above function into:

                        int Blah()
                        {
                        int k = 7;

                        return k += 4;
                        }

                        And return "k" itself, as it can see that there's no consequences of adding
                        the 4 to k directly. One less temporary.


                        -JKop

                        Comment

                        • cppaddict

                          #13
                          Re: How Methods Return Objects

                          JKop,

                          Thanks for that discussion... very interesting.

                          cpp

                          Comment

                          • Niels Dekker (no reply address)

                            #14
                            Re: How Methods Return Objects

                            cppaddict wrote:[color=blue]
                            >
                            > Point Point::operator +(const Point& p) const {
                            > Point ret(_x + p._x, _y + p._y);
                            > return ret;
                            > }[/color]

                            I would prefer having binary operators as non-member functions, like
                            this:

                            Point operator+(const Point& p1, const Point& p2) {
                            Point ret(p1._x + p2._x, p1._y + p2._y);
                            return ret;
                            }


                            What do you think?

                            Niels Dekker
                            Dekkerware freeware applications, source code included.

                            Comment

                            • Richard Herring

                              #15
                              Re: How Methods Return Objects

                              In message <410A2D7D.B658F FB3@this.is.inv alid>, "Niels Dekker (no reply
                              address)" <unknown@this.i s.invalid> writes[color=blue]
                              >cppaddict wrote:[color=green]
                              >>
                              >> Point Point::operator +(const Point& p) const {
                              >> Point ret(_x + p._x, _y + p._y);
                              >> return ret;
                              >> }[/color]
                              >
                              >I would prefer having binary operators as non-member functions, like
                              >this:
                              >
                              >Point operator+(const Point& p1, const Point& p2) {
                              > Point ret(p1._x + p2._x, p1._y + p2._y);
                              > return ret;
                              >}
                              >
                              >
                              >What do you think?[/color]

                              I think I'd implement non-member operator+() in terms of member
                              operator+=().


                              --
                              Richard Herring

                              Comment

                              Working...