константная ссылка на временное и копирование - C ++ - PullRequest
8 голосов
/ 05 марта 2010

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

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 ]

11 голосов
/ 05 марта 2010

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

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

const foo& f = foo();

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

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

1 голос
/ 05 марта 2010

Функция 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 голос
/ 05 марта 2010

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

0 голосов
/ 05 марта 2010

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.
...