Why is copy constructor not called when object is passed to function

I have the following code:

#include <iostream>
using namespace std;

  class foo
  {
      public:
          foo(int a, int b) :
              a_(a), b_(b)
          { cout << "regular const" << endl; }

          foo(const foo& f) :
              a_(f.a_), b_(f.b_)
          { cout << "copy const" << endl; }

          foo& operator=(const foo& rhs)
          {cout << "copy= const" << endl; a_ = rhs.a_; b_ = rhs.b_; return *this; }

          int a_, b_;
  };

  void bar(foo f)
  { }

  int main()
  {
      foo f1(10, 20);
      cout << "------" << endl;

      bar(f1);
      cout << "------" << endl;

      bar(foo(11, 22));            // line 29
      cout << "------" << endl;

      bar({13, 23});               // line 32
      cout << "------" << endl;    

  }

      

I am getting the following output:

$ ./a.out
regular const
------
copy const
------
regular const
------
regular const
------

      

For line 29 and line 32, I expected a temporary object to be instantiated in the main (normal constructor call) and then the copy constructor will be called when passed to bar (). From the output I can see that the compiler is doing some optimization and guessing, maybe just creating an object on the stack when bar () is called and only the normal constructor is called. Can someone please help me understand what type of optimization is being done or what is happening under the hood.

Is calling line () using lines 29 and 32 equivalent with respect to the generated code? I understand that line 29 is more readable.

I changed bar () as follows:

 void bar(const foo& f)
 { }

      

I get the same output for lines 29 and 32. In this case, where is the object created?

Thank you, Achmed.

+3


source to share


1 answer


On line 32

bar({13, 23});

      

the parameter is initialized for each copy list initialization - no intermediate temp is created, even in theory.

bar(foo(11, 22));

      

A copy of elision is used here. The compiler is allowed to exclude temporary, i.e. Build an object directly into a parameter:

This exception of copy / move operations, called copy, is allowed in the following cases (which can be combined with eliminate multiple copies):
[...]
- when an object of a temporary class that is not anchored to a link (12.2) is copied / moved into a class object with the same cv-unqualified type, the copy / move operation can be omitted by directly constructing the temporary object into the skipped copy / move target



If you want to see the result without any corrected copies or moves, use -fno-elide-constructors with GCC. It will produce the expected result. At least for line 32.

Now into the second version of the panel:

void bar(const foo& f)

      

On line 29, a temporary file is created and initialized from the bit-init list. On line 32, the reference is tied to a temporary argument. No optimizations or exceptions involved.

bar({13, 23});    // A temporary object is created as if by foo{13, 23},
                  // and the reference is bound to it

bar(foo(11, 22)); // The reference is bound to the temporary.
                  // The lifetime of the temporary has been extended.

      

+3


source







All Articles