оптимизация компилятора - PullRequest
11 голосов
/ 31 августа 2011

Итак, у меня есть к вам вопрос.:) Можете ли вы сказать мне вывод, который должен выдать следующий код?

#include <iostream>
struct Optimized
{
    Optimized() { std::cout << "ctor" << std::endl; }
    ~Optimized() { std::cout << "dtor" << std::endl; }
    Optimized(const Optimized& copy) { std::cout << "copy ctor" << std::endl; }
    Optimized(Optimized&& move) { std::cout << "move ctor" << std::endl; }
    const Optimized& operator=(const Optimized& rhs) { std::cout << "assignment operator" << std::endl; return *this; }
    Optimized& operator=(Optimized&& lhs) { std::cout << "move assignment operator" << std::endl; return *this; }
};

Optimized TestFunction()
{
    Optimized a;
    Optimized b = a;
    return b;
}

int main(int argc, char* argv[])
{
    Optimized test = TestFunction();
    return 0;
}

Мой первый ответ будет:

  1. ctor
  2. copy ctor
  3. move ctor
  4. dtor
  5. dtor
  6. dtor

, и это правда, но только если оптимизация компилятора включенаот .Когда оптимизация включена, выходной сигнал совершенно другой.При включенной оптимизации вывод:

  1. ctor
  2. copy ctor
  3. dtor
  4. dtor

При оптимизации компилятора тестовая переменная - это возвращаемая переменная.

Мой вопрос: какие условия могут привести к тому, что это не будет оптимизировано таким образом?

Меня всегда учили, что возвращать struct /Класс, который приводит к дополнительным конструкторам копирования, можно было бы лучше оптимизировать, передав его в качестве ссылки, но компилятор делает это для меня.Значит, возвращение - это все еще плохая форма?

Ответы [ 4 ]

14 голосов
/ 31 августа 2011

Это известно как Copy Elision и представляет собой специальную обработку вместо копирования / перемещения.

Стандарт специально разрешает оптимизацию при условии, что можно будет копировать / перемещать (т. Е. Метод объявлен и доступен).

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

  • RVO : при возврате временного (return "aa" + someString;)
  • NRVO : N для Именованный, когда вы возвращаете объект с именем

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

Поэтому, чтобы ответить на ваш вопрос о возврате структур: Я бы порекомендовал его . Рассмотрим:

// Bad
Foo foo;
bar(foo);

-- foo can be modified here


// Good
Foo const foo = bar();

Последнее не только понятнее, но и позволяет const принуждение!

4 голосов
/ 31 августа 2011

Оба выхода допустимы. Стандарт языка C ++ 03 в пункте 12.8 / 15 гласит:

При соблюдении определенных критериев реализация может опустить конструкцию копии объекта класса, даже если конструктор копирования и / или деструктор для объекта имеют побочные эффекты. В таких случаях реализация рассматривает источник и цель пропущенной операции копирования как просто два разных способа обращения к один и тот же объект, и разрушение этого объекта происходит в более поздние времена, когда два объекта был бы уничтожен без оптимизации. 111) Это исключение операций копирования разрешено в следующие обстоятельства (которые могут быть объединены для устранения нескольких копий):

  • в операторе return в функции с типом возвращаемого класса, когда выражение является именем энергонезависимый автоматический объект с тем же типом cv-unqualified, что и тип возвращаемого функцией, копия Операция может быть опущена путем создания автоматического объекта непосредственно в возвращаемое значение функции
  • когда временный объект класса, который не был связан со ссылкой (12.2), будет скопирован в класс объект с тем же типом cv-unqualified, операция копирования может быть опущена путем создания временного объект непосредственно в цель пропущенной копии
2 голосов
/ 31 августа 2011

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

То, произойдет это или нет, может зависеть от факторов, в том числе параметров оптимизации компилятора.

По моему мнению, называть вышеупомянутое определение копии "оптимизацией" не совсем правильно (хотя желание использовать этот термин здесь вполне понятно, и оно широко используется для этой цели). Я бы сказал, что термин оптимизация должен быть зарезервирован для ситуаций, когда компилятор отклоняет от поведения абстрактной машины C ++ , сохраняя при этом наблюдаемое поведение программа. Другими словами, истинная оптимизация подразумевает нарушение абстрактных требований спецификации языка. Поскольку в этом случае нарушения нет (исключение копирования явно разрешено стандартом), настоящей «оптимизации» не существует. Здесь мы наблюдаем только то, как язык C ++ работает на своем абстрактном уровне. Не нужно вовлекать понятие «оптимизация» вообще.

1 голос
/ 31 августа 2011

Даже при возврате по значению компилятор может оптимизировать лишнюю копию, используя Оптимизация возвращаемого значения см .; http://en.wikipedia.org/wiki/Return_value_optimization

...