C — передача rvalues в функцию по значениям

#c #c 11 #constructor #move-semantics

#c #c 11 #конструктор #переместить-семантика

Вопрос:

Я просто читаю «Эффективный современный C » Скотта Мейерса и тестирую такой код:

 class A
{
public:
    A(int _a) : a(_a)
    {   
        printf("Constructor A %dn",a);
    }
    A(Aamp;amp; tmp) noexcept
    {
        printf("MOVE constructorn");
        a=std::move(tmp.a);
    }
    A(const A amp; tmp)
    {
        printf("COPY constructorn");
        a= tmp.a;
    }
 private:
    int a;
 };
std::vector<A> v;
void fun(A temp)
{   
    v.push_back(std::move(temp));
}

void fun2(Aamp;amp; temp)
{
    v.push_back(std::move(temp));
}

int main()
{
    A x(3);
    fun(x);
    printf("n");
    fun(A(5));
    printf("n");
    fun2(A(6));
}
  

Вывод, который я вижу, является

 Constructor A 3
COPY constructor
MOVE constructor

Constructor A 5
MOVE constructor
MOVE constructor

Constructor A 6
MOVE constructor
MOVE constructor
MOVE constructor
  

У меня есть сомнения по поводу second call of fun. Оба конструктора перемещения используются во время

 v.push_back(std::move(temp));
  

Как это работает, что никакой конструктор перемещения не используется для создания param of fun? В первом случае вызывается конструктор копирования, поэтому я предполагаю, что во время второго вызова fun move должен быть вызван конструктор. Мой следующий вопрос заключается в том, как это работает в first call of fun

 v.push_back(std::move(temp));
  

вызывает только один конструктор перемещения, а второй call of fun вызывает 2 конструктора перемещения. Одна и та же строка вызывает конструктор перемещения 3 раза во время вызова fun2. Почему?

РЕДАКТИРОВАТЬ: Благодаря комментарию я добавил v.reserve (10), и теперь результаты выглядят намного лучше

 Constructor A 3
COPY constructor
MOVE constructor

Constructor A 5
MOVE constructor

Constructor A 6
MOVE constructor
  

Остался только один вопрос. Как получается, что caling

 fun(A(5))
  

не влияет ни на один конструктор? Это из-за оптимизации возвращаемого значения?

Комментарии:

1. Используйте v.reserve(10); перед вашими тестами, и ваш результат будет другим. cpp.sh/746u

2. IIRC: Когда вы объявляете новый экземпляр A внутри вызова функции, это неявно является ссылкой перемещения. Поскольку fun2 ожидается ссылка на перемещение, там также вызывается другой конструктор перемещения.

3. Тот факт, что f (A (5)) вызывает только один конструктор перемещения, действительно связан с оптимизацией возвращаемого типа (спецификация 12.8), A (5) создается в f parmeter temp.