mercredi 1 mai 2019

Missing a copy contructor call upon function call by value [duplicate]

This question already has an answer here:

First of all, I apologize if anything is not clear, this is my first post here.

So I have a C++11 issue... I often use this language and I recently came into the move semantics. So I started playing around with a toy example to have a clear understanding of what happens and when. However I got stuck with something that I don't understand and which is not even involving the move semantics (I think)...

In further details, I wrote a really simple class X - a wrapper around an array of int - in which I explicitly defined the default constructor as well as the copy constructor, the copy assignment operator, the move constructor, the move assignment operator and the destructor (for completeness). They all print a message.

From this, I added two other functions : one function to create an X instance and another one taking an X instance by value and displaying it.

The code is :

#include <iostream>

class X
{   public :
    int size ;
    int* arr ;

    // default constructor
    X()
    {   std::cout << "default constructor" << std::endl ;
        size = 0 ;
        arr = nullptr ;
    }

    // copy constructor
    X(const X& rhs)
    {   std::cout << "copy constructor" << std::endl ;
        size = rhs.size ;
        arr  = new int[size] ;
        for(int i=0; i<size; i++)
        {   arr[i] = rhs.arr[i] ; }
    }

    // copy assignment operator
    X& operator=(const X& rhs)
    {   std::cout << "copy assignment" << std::endl ;
        size = rhs.size ;
        arr  = new int[size] ;
        for(int i=0; i<size; i++)
        {   arr[i] = rhs.arr[i] ; }
        return *this ;
    }

    // move constructor
    X(X&& rhs)
    {   std::cout << "move constructor" << std::endl ;
        size = rhs.size ;
        // transfer ownership
        arr  = rhs.arr ;
        rhs.arr = nullptr ;
    }

    // move assignment operator
    X& operator=(X&& rhs)
    {   std::cout << "move assignment" << std::endl ;
        size = rhs.size  ;
        arr  = rhs.arr ;
        rhs.arr = nullptr ;
        return *this ;
    }

    // destructor
    ~X()
    {   std::cout << "destructor" << std::endl ;
        if(arr != nullptr)
        {   delete arr ;
            arr = nullptr ;
        }
    }

} ;

// simply receives an X object by value and displays it.
void foo(X x)
{
    std::cout << "----- foo(X) -----" << std::endl ;
    for(int i=0; i<x.size; i++)
    {   std::cout << x.arr[i] << " " ; }
    std::cout << std::endl ;
}

// creates an X object and returns it.
X createX()
{   std::cout << "----- createX() -----" << std::endl ;
    X x ;
    x.size=4 ;
    x.arr = new int[x.size] ;
    for(int i=0; i<x.size; i++)
    {   x.arr[i] = i ; }
    return x ;
}

int main()
{
    X x = createX() ;
    foo(x) ;
    foo(createX()) ;

    return 0 ;
}

I expected the following results :

----- createX() -----
default constructor    // inside createX()
copy constructor       // in the main(), 1st foo() call
----- foo(X) -----
0 1 2 3
destructor             // upon return from foo()
----- createX() -----
default constructor    // inside createX()
copy constructor       // in the main(), 2nd foo() call
----- foo(X) -----
0 1 2 3 
destructor             // upon return from foo()
destructor             // upon return from main()

But I got this instead :

----- createX() -----
default constructor
copy constructor
----- foo(X) -----
0 1 2 3 
destructor
----- createX() -----
default constructor
----- foo(X) -----     // missing the expected copy constructor call
0 1 2 3
destructor
destructor

which is missing the second "copy constructor" message I was expecting. So... what is happening at the second call of foo()? How is the anonymous instance given to the foo() if it is not copied using the copy constructor nor the move constructor?

Aucun commentaire:

Enregistrer un commentaire