Почему конструктор копирования не работает, когда я возвращаю автоматическую переменную из функции?

В приведенном ниже примере я хочу выяснить, почему конструктор копирования не вызывается, когда я возвращаю автоматическую переменную из функции doit(). Я понимаю, что первая версия обработчика вызывается, потому что у нас есть временный объект, но не могу понять, почему конструктор копирования не вызывается при создании этого временного объекта (копирует все из s во временный объект).

#include <iostream>
using namespace std;


class S{
    public:
        S(){std::cout<<"Constructor\n";}
        S(const S& s){std::cout<<"Copy Constructor\n";}
        ~S(){std::cout<<"Destructor\n";}
};

S doit(){
    S s;
    return s; 
}

void handler(S&& r){
    std::cout<<"Here\n";
}
void handler(const S& r){
    std::cout<<"Here2\n";
}

int main() {
    handler(doit());
}


person Erik Nouroyan    schedule 04.11.2020    source источник
comment
stackoverflow.com/ вопросы/12953127/   -  person rafix07    schedule 04.11.2020


Ответы (1)


На самом деле в вашем коде есть конструктор, который вызывается в соответствии с правилами языка. Однако компилятор оптимизировал это, и поэтому вы не видите вызова. Если вы скомпилируете с -fno-elide-constructors, вы должны увидеть, как вызывается конструктор копирования.

Обратите внимание, что конструктор копирования будет вызываться только потому, что конструктор перемещения по умолчанию подавлен. Если вы добавите это обратно следующим образом:

S(S&&) = default;

то вместо этого будет вызываться этот конструктор перемещения. Вот демонстрация.

person cigien    schedule 04.11.2020
comment
Так и думал, но не был уверен, так как скомпилировал в онлайн-компиляторе - person Erik Nouroyan; 04.11.2020
comment
@ErikNouroyan Использование онлайн-компилятора не должно иметь никакого значения. - person cigien; 04.11.2020
comment
На самом деле это так, добавление S(S&&) = default; не приводит к вызову конструктора копирования - person Erik Nouroyan; 04.11.2020
comment
@ErikNouroyan Да, но потому что вызывается конструктор перемещения. (это не имеет ничего общего с онлайн-компилятором). См. демо-ссылку, где я cout в этом конструкторе, а не по умолчанию, чтобы вы могли ясно видеть вызов. - person cigien; 04.11.2020
comment
Ах, теперь я понял, спасибо, если я это сделаю S(S&&) = delete;, я надеюсь, что он должен вызвать конструктор копирования - person Erik Nouroyan; 04.11.2020
comment
@ErikNouroyan Да, будет. Обратите внимание, что вам даже не нужно =delete перемещать конструктор, так как в этом случае он все равно не генерируется. - person cigien; 04.11.2020
comment
На самом деле это не сработало, более того, когда я добавляю cout к этому S(S&&), он не показывает сообщение, я думаю, это зависит от компилятора - person Erik Nouroyan; 04.11.2020
comment
@ErikNouroyan Нет, это зависит от флага, который я упомянул в ответе. Без явной передачи этого флага компиляторы по умолчанию оптимизируют такие вызовы уже как минимум 20 лет. - person cigien; 04.11.2020
comment
@ErikNouroyan Нет проблем :) Подумайте о том, чтобы принять ответ, если он действительно отвечает на ваш вопрос. - person cigien; 04.11.2020