Константная ссылка на временное и копирование - C++

Пожалуйста, рассмотрите следующий код,

struct foo
{
    foo()
    {
        std::cout << "Constructing!" << std::endl;
    }

    foo(const foo& f)
    {
        std::cout << "Copy constructing!" << std::endl;
    }

    ~foo()
    {
        std::cout << "Destructing.." << std::endl;
    }
};

foo get()
{
    foo f;
    return f;
}

int main()
{
    const foo& f = get();
    std::cout << "before return" << std::endl;
    return 0;
}

Выход на MSVC

Constructing!
Copy constructing!
Destructing..
before return
Destructing..

Выход GCC

Constructing!
before return
Destructing..

Результат, который приходит на MSVC выглядит некорректно.

Вопросы

  1. AFAIK, GCC дает правильный результат здесь. Почему MSVC дает разные результаты и почему он создает копии?
  2. const foo& f = get() а также const foo f = get() производит тот же результат из-за оптимизации возвращаемого значения. В этом случае какой способ письма должен быть предпочтительным?

Какие-нибудь мысли..

4 ответа

Решение

Ваша сборка MSVC не имеет оптимизаций. Включите их, вы получите одинаковый вывод для обоих.

GCC по умолчанию просто выполняет RVO на вашем временном сервере. Это в основном делает:

const foo& f = foo();

MSVC нет. Это делает foo в функции, копируя ее извне функции (например, вызов конструктора копирования), разрушая внутренний foo, а затем связывает ссылку.

Оба выхода верны. RVO - это тот случай, когда стандарт явно позволяет изменять наблюдаемое поведение программы.

Вы видите оптимизацию возвращаемого значения, которая является одним из видов копирования. Обе программы верны; компилятору, в частности, предоставляется возможность исключить временный объект, который служит только для перемещения данных из одного постоянного объекта в другой.

Функция get () - это конструирование локального (печатать построение!) И возвращение объекта Foo по значению. Возвращаемый объект Foo должен быть создан с помощью конструкции копирования (печать Создайте копию!). Обратите внимание, что это значение объекта, присвоенное const foo & f в main.

Однако до того, как это назначение произойдет, функция должна вернуться из get (), а локальные переменные (т.е. foo f; в get ()) должны быть уничтожены. (печать 1st Destructing..) Оттуда программа завершается (то есть возвращается из main), затем объект, возвращенный get () и назначенный на "f", уничтожается. (печать 2-го уничтожения...)

Причина, по которой вы видите разные выходные данные для двух компиляторов, заключается в том, что GCC оптимизирует возвращаемое значение для get () и просто заменяет const foo &f = get() в const foo &f = foo;

1) Это происходит из-за другой стратегии оптимизации. Поскольку у вас нет оператора =, MSVC может реструктурировать код в нечто вроде const foo& f(get()), поэтому выполняет копирование onstructor. 2) Зависит от того, что вы хотите достичь:

const foo& f = get();
f = get(); // Incorrect, const references cannot be reassigned.
const foo g = get();
g = get(); // Correct.
Другие вопросы по тегам