Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::pair from temporary: Why is copy constructor called and not move constructor?

Tags:

c++

std-pair

move

Consider the following code:

#include<iostream>
using namespace std;
struct A {
    A(const A&){
        cout<<"copy constructor"<<endl;
    }
    A(A&&){
        cout<<"move constructor"<<endl;
    }
    ~A(){
        cout<<"destructor"<<endl;
    }
    static std::pair<A,int> f1()
    {
        int i = 1;
        return std::pair<A,int>{i,2};
    }
    static std::pair<A,int> f2()
    {
        int i = 1;
        return std::pair<A,int>{A(i),2};
    }
    private:
    A(int){
        cout<<"constructor"<<endl;
    }
};

int main()
{
    cout<<"f1: "<<endl;
    A::f1();
    cout<<"f2: "<<endl;
    A::f2();
}

The constructor A(int) is private, therefore the A in the pair<A,int> cannot be in place constructed from an int. Hence, a temporary is constructed in f1. In f2 I create the temporary explicitly but the behavior is different, the output is:

f1: 
constructor
copy constructor
destructor
destructor
f2: 
constructor
move constructor
destructor
destructor

I would expect the move constructor to be called also in A::f1 but the copy constructor is called which is sub optimal. Why is this the case?

like image 253
phinz Avatar asked Mar 12 '26 14:03

phinz


1 Answers

If you look at pair's constructors

Interesting constructors are (2) and (3)

// (2)
constexpr pair( const T1& x, const T2& y );

// (3)
template< class U1 = T1, class U2 = T2 >
constexpr pair( U1&& x, U2&& y ); // SFINAE on constructible

Notice, there are no pair(T1&&, T2&&).

As A(int) is private, std::is_constructible_v<A, int> is false.

So for f1, only (2) is a viable constructor (so the copy).

For f2, (3) is viable (and better match), so a forward (so a move) is done.

like image 74
Jarod42 Avatar answered Mar 15 '26 03:03

Jarod42