константная ссылка на временную и копируемую - С++

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

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. Насколько мне известно, GCC дает здесь правильный результат. Почему MSVC дает разные результаты и почему он создает копии?
  2. const foo& f = get() и const foo f = get() дают одинаковый результат из-за оптимизации возвращаемого значения. В этом случае, какой способ написания следует предпочесть?

Есть идеи..


person Navaneeth K N    schedule 05.03.2010    source источник
comment
Это потому, что в gcc по умолчанию включен RVO. Чтобы отключить это, используйте параметр gcc -fno-elide-constructors.   -  person Prasoon Saurav    schedule 05.03.2010


Ответы (4)


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

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

const foo& f = foo();

МСВК нет. Он создает foo в функции, копирует его за пределы функции (следовательно, вызов конструктора копирования), уничтожает внутренний foo, а затем привязывает ссылку.

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

person GManNickG    schedule 05.03.2010
comment
Да. Я только что обнаружил это сейчас. Я изменил уровень оптимизации, и он ведет себя одинаково. - person Navaneeth K N; 05.03.2010
comment
Итак, какой способ письма вы рекомендуете? const foo& f = get() или const foo f = get()? - person Navaneeth K N; 05.03.2010
comment
@Appu: Хм, наверное, первое. В любом случае, в универсальном коде вы бы хотели, чтобы const T& избегал копий, если, например, правая часть является контейнером. Так что для согласованности можно также сделать const foo&. Тем не менее, некоторым это может показаться странным, так что я на заборе. - person GManNickG; 05.03.2010
comment
Спасибо GMan и другим за помощь... :) - person Navaneeth K N; 05.03.2010
comment
Также, вероятно, стоит отметить, что в С++ 0x первому разрешено копировать возвращаемое значение перед привязкой ссылки const. В C++0x такое копирование запрещено: пока вызываемая функция имеет доступ к конструктору копирования (чтобы скопировать локальную переменную в возвращаемое значение), строка должна быть в порядке (вызывающему коду больше не требуется доступ к копии). конструктор). - person Johannes Schaub - litb; 05.03.2010

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

person Potatoswatter    schedule 05.03.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;

person RC.    schedule 05.03.2010

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

const foo& f = get();
f = get(); // Incorrect, const references cannot be reassigned.
const foo g = get();
g = get(); // Correct.
person Sad Developer    schedule 05.03.2010
comment
Я думаю, вы совершенно неправильно понимаете значение модификатора const. г = получить(); тоже ошибка. - person Ben Voigt; 05.03.2010
comment
Ты прав. Мои знания C++ испорчены 2,5 годами тестирования :( - person Sad Developer; 05.03.2010