ссылка константы на временный и копирующий - 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() производит тот же вывод из-за оптимизации возвращаемого значения. В этом случае, какой способ записать должен быть предпочтен?

Любые мысли..

8
задан James McNellis 12 July 2010 в 13:14
поделиться

4 ответа

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

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

const foo& f = foo();

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

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

11
ответ дан 5 December 2019 в 15:22
поделиться

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

1
ответ дан 5 December 2019 в 15:22
поделиться

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

const foo& f = get();
f = get(); // Incorrect, const references cannot be reassigned.
const foo g = get();
g = get(); // Correct.
-2
ответ дан 5 December 2019 в 15:22
поделиться

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

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

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

1
ответ дан 5 December 2019 в 15:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: