Почему конструктор копирования вызывается дважды в этом фрагменте кода? - PullRequest
0 голосов
/ 28 февраля 2019

Я играю с несколькими вещами, чтобы понять, как работают конструкторы копирования.Но я не могу понять, почему конструктор копирования вызывается дважды для создания x2.Я бы предположил, что он будет вызван один раз, когда возвращаемое значение createX() копируется в x2.
Я также рассмотрел несколько связанных вопросов по SO, но, насколько я могу судить, не смог найтитот же простой сценарий, который я спрашиваю здесь.

Кстати, я компилирую с -fno-elide-constructors, чтобы увидеть, что происходит без оптимизации.

#include <iostream>

struct X {
    int i{2};

    X() {
        std::cout << "default constructor called" << std::endl;
    }

    X(const X& other) {
        std::cout << "copy constructor called" << std::endl;
    }
};

X createX() {
    X x;
    std::cout << "created x on the stack" << std::endl;
    return x;
}

int main() {
    X x1;
    std::cout << "created x1" << std::endl;
    std::cout << "x1: " << x1.i << std::endl << std::endl;    

    X x2 = createX();
    std::cout << "created x2" << std::endl;
    std::cout << "x2: " << x2.i << std::endl;    

    return 0;
}

Это вывод:

default constructor called
created x1
x1: 2

default constructor called
created x on the stack
copy constructor called
copy constructor called
created x2
x2: 2

Может ли кто-нибудь помочь мне, что я здесь пропускаю или пропускаю?

Ответы [ 2 ]

0 голосов
/ 28 февраля 2019

Здесь вы должны помнить, что возвращаемое значение функции - это отдельный объект.Когда вы делаете

return x;

, вы копируете инициализируемый объект возвращаемого значения с x.Это первый вызов конструктора копирования, который вы видите.Затем

X x2 = createX();

использует возвращенный объект для копирования инициализации x2, так что это вторая копия, которую вы видите.


Следует отметить, что

return x;

попытается переместить x в возвращаемый объект, если сможет.Если бы вы сделали конструктор перемещения, вы бы увидели, что это называется.Причина этого заключается в том, что поскольку локальные объекты выходят из области видимости в конце функции, компилятор обрабатывает объект как значение r и только в том случае, если он не находит допустимой перегрузки, он возвращается к возвращению его как lvalue.

0 голосов
/ 28 февраля 2019

Первая копия взята из createX

X createX() {
    X x;
    std::cout << "created x on the stack" << std::endl;
    return x; // First copy
}

Вторая - создать x2 из временного возврата из createX.

X x2 = createX(); // Second copy

Обратите внимание, что в C ++ 17 втораякопия должна быть удалена.

...