Как создается локальная переменная в функциях?

Допустим, у меня есть этот код:

#include <iostream>
using namespace std;

class A{
public:
    A() { cout << "In normal ctor\n"; }
    A(const A& a) { cout << "In cpy ctor\n";  }
    A(A&& a) { cout << "In move ctor\n"; }
    ~A() { cout << "In dtor\n"; }
};

A func(A a) {
    return a;
}

void main(){
    A a1;
    A a2 = func(a1);
}

Вывод следующий:

In normal ctor
In cpy ctor
In move ctor
In dtor
In dtor
In dtor

Теперь мне трудно понять, что происходит внутри функции func.

Когда a1 отправляется в функцию, функция не получает его по ссылке, а скорее «создает» свою собственную версию a1, которая является «a».

Поэтому, когда функция завершается, объект "умирает" и уходит в деструктор.

Так почему же он не передается конструктору? (Предположим, что там действительно создан локальный объект)

Есть ли какое-либо копирование, которое происходит за кулисами?

Заранее спасибо!


person Martin    schedule 12.02.2018    source источник
comment
Так почему же он также не переходит к конструктору? Он делает In cpy ctor   -  person tkausl    schedule 12.02.2018
comment
but rather it "creates" it's own version, да, это называется копированием, и вы видите это в In cpy ctor.   -  person freakish    schedule 12.02.2018
comment
@tkausl, но разве копия не из-за A a2 = func (a1)? Это не внутри функции   -  person Martin    schedule 12.02.2018
comment
@ Мартин, нет, это задание оптимизировано для построения перемещения, In move ctor.   -  person freakish    schedule 12.02.2018
comment
@freakish, о, я вижу, конструктор копирования происходит из-за «создания» в функции? а ход на самом деле в основном? (потому что это RVALUE)   -  person Martin    schedule 12.02.2018
comment
@Мартин: Верно.   -  person Lightness Races in Orbit    schedule 13.02.2018


Ответы (3)


Вот что получается (распечатки вашей программы с пояснениями):

  • В обычном ctor — это происходит в A a1; из main
  • В копирайтере. Это происходит, когда A a из func инициализируются из a1 из main.
  • In move ctor. Это происходит, когда a из func, копия a1, устанавливается в a2 (см. copy исключение взамен)
  • In dtor — копия a1 уничтожена
  • In dtora2 уничтожен
  • In dtora1 уничтожен

Я думаю, что ключевым моментом здесь является понимание роли конструктора перемещения в создании a2. Ваш func возвращает A по значению, которое должно быть скопировано в a2. Однако компилятор C++ понимает, что ваша программа не может использовать исходное значение после присваивания, поэтому оптимизирует вызов, вызывая конструктор перемещения.

person Sergey Kalinichenko    schedule 12.02.2018
comment
Большое спасибо! Теперь я вижу ошибку, которая у меня была, я думал, что конструктор копирования происходит в основном, когда он фактически происходит в функции, поэтому на самом деле он создает «а»! - person Martin; 12.02.2018

void main(){
    A a1; -- > Normal constructor
    A a2 = func(a1); --> Copy(a1 to a), Move(a to a2), destructor(a)
} -->  destructor a1, a2

Вот почему вы видите вывод в таком порядке.

person AdityaG    schedule 12.02.2018

func передается копией A (т.е. нет ссылки, и это не указатель и т. д.). Вот почему вызывается конструктор копирования. После того, как он создан, он перемещается в позицию a2, таким образом, конструктор перемещения. После перемещения a уничтожается (поскольку func возвращается и выходит за пределы области видимости), а затем обе a1 и a2 (поскольку возвращается main).

Вы спросили, почему он не входит в конструктор, но он входит. Для каждого A, который вы создаете, вызывается другой конструктор, сначала a1 (обычно), затем in func (через копирование) и, наконец, a2 (через перемещение).

person Garrett Gutierrez    schedule 12.02.2018