Copy constructor not called when initializing an object with return value of a function

前端 未结 2 1947
别跟我提以往
别跟我提以往 2021-02-06 04:11

Consider the following code:

#include 

using namespace std;

class A
{
    public:
        int a;
        A(): a(5)
        {
           cout &l         


        
相关标签:
2条回答
  • 2021-02-06 04:18
    #include <iostream>
    
    using namespace std;
    
    class A
    {
    public:
        int a;
        A(): a(5)
        {
            cout << "Constructing: " << (void *)this << std::endl;
        }
        A(const A &b)
        {
            a = b.a;
            cout << "Copy Constructor: " << (void *)this << " from " << (void *)&b << std::endl;
        }
        A fun(A a)
        {
            return a;
        }
    };
    
    int main()
    {
    
        A a, c;
        A b = a.fun(c);
    
        std::cout << "a:" << (void *)&a << std::endl <<
                  "b:" << (void *)&b << std::endl <<
                  "c:" << (void *)&c << std::endl;
        return 0;
    }
    

    Yields:

    Constructing: 0x7fffbb377220
    Constructing: 0x7fffbb377210
    Copy Constructor: 0x7fffbb377230 from 0x7fffbb377210
    Copy Constructor: 0x7fffbb377200 from 0x7fffbb377230
    a:0x7fffbb377220
    b:0x7fffbb377200
    c:0x7fffbb377210
    

    So it constructs a, constructs c, copies c to an intermediate (argument a of the function), and then copies the intermediate directly into b, skipping the typical copying of a to a return intermediate. This is even better demonstrated if you pass by value (change to A fun(const A& a):

    Constructing: 0x7fff8e9642b0
    Constructing: 0x7fff8e9642a0
    Copy Constructor: 0x7fff8e964290 from 0x7fff8e9642a0
    a:0x7fff8e9642b0
    b:0x7fff8e964290
    c:0x7fff8e9642a0
    

    a is constructed, c is constructed, c is copied directly to b, despite b not being passed to fun!

    0 讨论(0)
  • 2021-02-06 04:31

    The copy that is elided is the copy of the temporary return value into b. Without elision the return value is initialized from a and copied to b. Instead, the temporary that would otherwise hold the return value is constructed into b and initialized with a. [class.copy]/31:

    when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

    You can observe this if you add an additional output in fun:

    A fun(A a)
    {
        cout << "fun!" << endl;
        return a;
    }
    

    Then with the elision you'll get

    […]
    fun!
    Copy Constructor

    And without:

    […]
    fun!
    Copy Constructor
    Copy Constructor

    0 讨论(0)
提交回复
热议问题