Why is the copy constructor called twice in this code snippet?












8















I'm playing around with a few things to understand how copy constructors work. But I can't make sense of why the copy constructor is called twice for the creation of x2. I would have assumed it would be called once when the return value of createX() is copied into x2.

I also looked at a few related questions on SO, but as far as I can tell I couldn't find the same simple scenario as I am asking here.



By the way, I'm compiling with -fno-elide-constructors in order to see what's going on without optimizations.



#include <iostream>

struct X {
int i{2};

X() {
std::cout << "default constructor called" << std::endl;
}

X(const X& other) {
std::cout << "copy constructor called" << std::endl;
}
};

X createX() {
X x;
std::cout << "created x on the stack" << std::endl;
return x;
}

int main() {
X x1;
std::cout << "created x1" << std::endl;
std::cout << "x1: " << x1.i << std::endl << std::endl;

X x2 = createX();
std::cout << "created x2" << std::endl;
std::cout << "x2: " << x2.i << std::endl;

return 0;
}


This is the output:



default constructor called
created x1
x1: 2

default constructor called
created x on the stack
copy constructor called
copy constructor called
created x2
x2: 2


Can someone help me what I'm missing or overlooking here?










share|improve this question









New contributor




c_student is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

























    8















    I'm playing around with a few things to understand how copy constructors work. But I can't make sense of why the copy constructor is called twice for the creation of x2. I would have assumed it would be called once when the return value of createX() is copied into x2.

    I also looked at a few related questions on SO, but as far as I can tell I couldn't find the same simple scenario as I am asking here.



    By the way, I'm compiling with -fno-elide-constructors in order to see what's going on without optimizations.



    #include <iostream>

    struct X {
    int i{2};

    X() {
    std::cout << "default constructor called" << std::endl;
    }

    X(const X& other) {
    std::cout << "copy constructor called" << std::endl;
    }
    };

    X createX() {
    X x;
    std::cout << "created x on the stack" << std::endl;
    return x;
    }

    int main() {
    X x1;
    std::cout << "created x1" << std::endl;
    std::cout << "x1: " << x1.i << std::endl << std::endl;

    X x2 = createX();
    std::cout << "created x2" << std::endl;
    std::cout << "x2: " << x2.i << std::endl;

    return 0;
    }


    This is the output:



    default constructor called
    created x1
    x1: 2

    default constructor called
    created x on the stack
    copy constructor called
    copy constructor called
    created x2
    x2: 2


    Can someone help me what I'm missing or overlooking here?










    share|improve this question









    New contributor




    c_student is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.























      8












      8








      8








      I'm playing around with a few things to understand how copy constructors work. But I can't make sense of why the copy constructor is called twice for the creation of x2. I would have assumed it would be called once when the return value of createX() is copied into x2.

      I also looked at a few related questions on SO, but as far as I can tell I couldn't find the same simple scenario as I am asking here.



      By the way, I'm compiling with -fno-elide-constructors in order to see what's going on without optimizations.



      #include <iostream>

      struct X {
      int i{2};

      X() {
      std::cout << "default constructor called" << std::endl;
      }

      X(const X& other) {
      std::cout << "copy constructor called" << std::endl;
      }
      };

      X createX() {
      X x;
      std::cout << "created x on the stack" << std::endl;
      return x;
      }

      int main() {
      X x1;
      std::cout << "created x1" << std::endl;
      std::cout << "x1: " << x1.i << std::endl << std::endl;

      X x2 = createX();
      std::cout << "created x2" << std::endl;
      std::cout << "x2: " << x2.i << std::endl;

      return 0;
      }


      This is the output:



      default constructor called
      created x1
      x1: 2

      default constructor called
      created x on the stack
      copy constructor called
      copy constructor called
      created x2
      x2: 2


      Can someone help me what I'm missing or overlooking here?










      share|improve this question









      New contributor




      c_student is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.












      I'm playing around with a few things to understand how copy constructors work. But I can't make sense of why the copy constructor is called twice for the creation of x2. I would have assumed it would be called once when the return value of createX() is copied into x2.

      I also looked at a few related questions on SO, but as far as I can tell I couldn't find the same simple scenario as I am asking here.



      By the way, I'm compiling with -fno-elide-constructors in order to see what's going on without optimizations.



      #include <iostream>

      struct X {
      int i{2};

      X() {
      std::cout << "default constructor called" << std::endl;
      }

      X(const X& other) {
      std::cout << "copy constructor called" << std::endl;
      }
      };

      X createX() {
      X x;
      std::cout << "created x on the stack" << std::endl;
      return x;
      }

      int main() {
      X x1;
      std::cout << "created x1" << std::endl;
      std::cout << "x1: " << x1.i << std::endl << std::endl;

      X x2 = createX();
      std::cout << "created x2" << std::endl;
      std::cout << "x2: " << x2.i << std::endl;

      return 0;
      }


      This is the output:



      default constructor called
      created x1
      x1: 2

      default constructor called
      created x on the stack
      copy constructor called
      copy constructor called
      created x2
      x2: 2


      Can someone help me what I'm missing or overlooking here?







      c++ c++14 copy-constructor






      share|improve this question









      New contributor




      c_student is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      c_student is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 12 hours ago









      NathanOliver

      93.8k16130199




      93.8k16130199






      New contributor




      c_student is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 12 hours ago









      c_studentc_student

      635




      635




      New contributor




      c_student is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      c_student is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      c_student is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.
























          2 Answers
          2






          active

          oldest

          votes


















          13














          What you have to remember here is that the return value of a function is a distinct object. When you do



          return x;


          you copy initialize the return value object with x. This is the first copy constructor call you see. Then



          X x2 = createX();


          uses the returned object to copy initialize x2 so that is the second copy you see.





          One thing to note is that



          return x;


          will try to move x into the return object if it can. Had you made a move constructor you would have seen this called. The reason for this is that since local objects go out of scope at the end of the function, the compiler treats the object as an rvalue and only if that does not find a valid overload does it fall back to returning it as an lvalue.






          share|improve this answer


























          • @FrançoisAndrieux Yeah. Updating the wording to make that more explicit that isn't something that is just allowed but has to be done.

            – NathanOliver
            12 hours ago











          • I'm not sure of the details of -fno-elide-constructors but I'm assuming it prevents RVO.

            – François Andrieux
            12 hours ago











          • @FrançoisAndrieux It does not prevent guaranteed RVO if using C++17 since that is mandated that it has to happen, there isn't actually a temporary object created. See here where it only uses a single copy as the second one is mandated not to happen.

            – NathanOliver
            12 hours ago











          • So we have to assume OP is using a pre-C++17 standard?

            – François Andrieux
            12 hours ago











          • Kind of. The compiler they are using could have a bug, or they are using pre C++17. I'm inclined to believe it is the latter.

            – NathanOliver
            12 hours ago



















          9














          First copy is in return of createX



          X createX() {
          X x;
          std::cout << "created x on the stack" << std::endl;
          return x; // First copy
          }


          Second one is to create x2 from the temporary return by createX.



          X x2 = createX(); // Second copy


          Notice that in C++17, second copy is forced to be elided.






          share|improve this answer























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });






            c_student is a new contributor. Be nice, and check out our Code of Conduct.










            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54929274%2fwhy-is-the-copy-constructor-called-twice-in-this-code-snippet%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            13














            What you have to remember here is that the return value of a function is a distinct object. When you do



            return x;


            you copy initialize the return value object with x. This is the first copy constructor call you see. Then



            X x2 = createX();


            uses the returned object to copy initialize x2 so that is the second copy you see.





            One thing to note is that



            return x;


            will try to move x into the return object if it can. Had you made a move constructor you would have seen this called. The reason for this is that since local objects go out of scope at the end of the function, the compiler treats the object as an rvalue and only if that does not find a valid overload does it fall back to returning it as an lvalue.






            share|improve this answer


























            • @FrançoisAndrieux Yeah. Updating the wording to make that more explicit that isn't something that is just allowed but has to be done.

              – NathanOliver
              12 hours ago











            • I'm not sure of the details of -fno-elide-constructors but I'm assuming it prevents RVO.

              – François Andrieux
              12 hours ago











            • @FrançoisAndrieux It does not prevent guaranteed RVO if using C++17 since that is mandated that it has to happen, there isn't actually a temporary object created. See here where it only uses a single copy as the second one is mandated not to happen.

              – NathanOliver
              12 hours ago











            • So we have to assume OP is using a pre-C++17 standard?

              – François Andrieux
              12 hours ago











            • Kind of. The compiler they are using could have a bug, or they are using pre C++17. I'm inclined to believe it is the latter.

              – NathanOliver
              12 hours ago
















            13














            What you have to remember here is that the return value of a function is a distinct object. When you do



            return x;


            you copy initialize the return value object with x. This is the first copy constructor call you see. Then



            X x2 = createX();


            uses the returned object to copy initialize x2 so that is the second copy you see.





            One thing to note is that



            return x;


            will try to move x into the return object if it can. Had you made a move constructor you would have seen this called. The reason for this is that since local objects go out of scope at the end of the function, the compiler treats the object as an rvalue and only if that does not find a valid overload does it fall back to returning it as an lvalue.






            share|improve this answer


























            • @FrançoisAndrieux Yeah. Updating the wording to make that more explicit that isn't something that is just allowed but has to be done.

              – NathanOliver
              12 hours ago











            • I'm not sure of the details of -fno-elide-constructors but I'm assuming it prevents RVO.

              – François Andrieux
              12 hours ago











            • @FrançoisAndrieux It does not prevent guaranteed RVO if using C++17 since that is mandated that it has to happen, there isn't actually a temporary object created. See here where it only uses a single copy as the second one is mandated not to happen.

              – NathanOliver
              12 hours ago











            • So we have to assume OP is using a pre-C++17 standard?

              – François Andrieux
              12 hours ago











            • Kind of. The compiler they are using could have a bug, or they are using pre C++17. I'm inclined to believe it is the latter.

              – NathanOliver
              12 hours ago














            13












            13








            13







            What you have to remember here is that the return value of a function is a distinct object. When you do



            return x;


            you copy initialize the return value object with x. This is the first copy constructor call you see. Then



            X x2 = createX();


            uses the returned object to copy initialize x2 so that is the second copy you see.





            One thing to note is that



            return x;


            will try to move x into the return object if it can. Had you made a move constructor you would have seen this called. The reason for this is that since local objects go out of scope at the end of the function, the compiler treats the object as an rvalue and only if that does not find a valid overload does it fall back to returning it as an lvalue.






            share|improve this answer















            What you have to remember here is that the return value of a function is a distinct object. When you do



            return x;


            you copy initialize the return value object with x. This is the first copy constructor call you see. Then



            X x2 = createX();


            uses the returned object to copy initialize x2 so that is the second copy you see.





            One thing to note is that



            return x;


            will try to move x into the return object if it can. Had you made a move constructor you would have seen this called. The reason for this is that since local objects go out of scope at the end of the function, the compiler treats the object as an rvalue and only if that does not find a valid overload does it fall back to returning it as an lvalue.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 12 hours ago

























            answered 12 hours ago









            NathanOliverNathanOliver

            93.8k16130199




            93.8k16130199













            • @FrançoisAndrieux Yeah. Updating the wording to make that more explicit that isn't something that is just allowed but has to be done.

              – NathanOliver
              12 hours ago











            • I'm not sure of the details of -fno-elide-constructors but I'm assuming it prevents RVO.

              – François Andrieux
              12 hours ago











            • @FrançoisAndrieux It does not prevent guaranteed RVO if using C++17 since that is mandated that it has to happen, there isn't actually a temporary object created. See here where it only uses a single copy as the second one is mandated not to happen.

              – NathanOliver
              12 hours ago











            • So we have to assume OP is using a pre-C++17 standard?

              – François Andrieux
              12 hours ago











            • Kind of. The compiler they are using could have a bug, or they are using pre C++17. I'm inclined to believe it is the latter.

              – NathanOliver
              12 hours ago



















            • @FrançoisAndrieux Yeah. Updating the wording to make that more explicit that isn't something that is just allowed but has to be done.

              – NathanOliver
              12 hours ago











            • I'm not sure of the details of -fno-elide-constructors but I'm assuming it prevents RVO.

              – François Andrieux
              12 hours ago











            • @FrançoisAndrieux It does not prevent guaranteed RVO if using C++17 since that is mandated that it has to happen, there isn't actually a temporary object created. See here where it only uses a single copy as the second one is mandated not to happen.

              – NathanOliver
              12 hours ago











            • So we have to assume OP is using a pre-C++17 standard?

              – François Andrieux
              12 hours ago











            • Kind of. The compiler they are using could have a bug, or they are using pre C++17. I'm inclined to believe it is the latter.

              – NathanOliver
              12 hours ago

















            @FrançoisAndrieux Yeah. Updating the wording to make that more explicit that isn't something that is just allowed but has to be done.

            – NathanOliver
            12 hours ago





            @FrançoisAndrieux Yeah. Updating the wording to make that more explicit that isn't something that is just allowed but has to be done.

            – NathanOliver
            12 hours ago













            I'm not sure of the details of -fno-elide-constructors but I'm assuming it prevents RVO.

            – François Andrieux
            12 hours ago





            I'm not sure of the details of -fno-elide-constructors but I'm assuming it prevents RVO.

            – François Andrieux
            12 hours ago













            @FrançoisAndrieux It does not prevent guaranteed RVO if using C++17 since that is mandated that it has to happen, there isn't actually a temporary object created. See here where it only uses a single copy as the second one is mandated not to happen.

            – NathanOliver
            12 hours ago





            @FrançoisAndrieux It does not prevent guaranteed RVO if using C++17 since that is mandated that it has to happen, there isn't actually a temporary object created. See here where it only uses a single copy as the second one is mandated not to happen.

            – NathanOliver
            12 hours ago













            So we have to assume OP is using a pre-C++17 standard?

            – François Andrieux
            12 hours ago





            So we have to assume OP is using a pre-C++17 standard?

            – François Andrieux
            12 hours ago













            Kind of. The compiler they are using could have a bug, or they are using pre C++17. I'm inclined to believe it is the latter.

            – NathanOliver
            12 hours ago





            Kind of. The compiler they are using could have a bug, or they are using pre C++17. I'm inclined to believe it is the latter.

            – NathanOliver
            12 hours ago













            9














            First copy is in return of createX



            X createX() {
            X x;
            std::cout << "created x on the stack" << std::endl;
            return x; // First copy
            }


            Second one is to create x2 from the temporary return by createX.



            X x2 = createX(); // Second copy


            Notice that in C++17, second copy is forced to be elided.






            share|improve this answer




























              9














              First copy is in return of createX



              X createX() {
              X x;
              std::cout << "created x on the stack" << std::endl;
              return x; // First copy
              }


              Second one is to create x2 from the temporary return by createX.



              X x2 = createX(); // Second copy


              Notice that in C++17, second copy is forced to be elided.






              share|improve this answer


























                9












                9








                9







                First copy is in return of createX



                X createX() {
                X x;
                std::cout << "created x on the stack" << std::endl;
                return x; // First copy
                }


                Second one is to create x2 from the temporary return by createX.



                X x2 = createX(); // Second copy


                Notice that in C++17, second copy is forced to be elided.






                share|improve this answer













                First copy is in return of createX



                X createX() {
                X x;
                std::cout << "created x on the stack" << std::endl;
                return x; // First copy
                }


                Second one is to create x2 from the temporary return by createX.



                X x2 = createX(); // Second copy


                Notice that in C++17, second copy is forced to be elided.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered 12 hours ago









                Jarod42Jarod42

                117k12103186




                117k12103186






















                    c_student is a new contributor. Be nice, and check out our Code of Conduct.










                    draft saved

                    draft discarded


















                    c_student is a new contributor. Be nice, and check out our Code of Conduct.













                    c_student is a new contributor. Be nice, and check out our Code of Conduct.












                    c_student is a new contributor. Be nice, and check out our Code of Conduct.
















                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54929274%2fwhy-is-the-copy-constructor-called-twice-in-this-code-snippet%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    "Incorrect syntax near the keyword 'ON'. (on update cascade, on delete cascade,)

                    Alcedinidae

                    RAC Tourist Trophy