Мне известны 5 общих категорий, в которых перекомпиляция компилятора C ++ 03 в C ++ 11 может привести к неограниченному увеличению производительности, которое практически не связано с качеством реализации. Это все вариации семантики перемещения.
std::vector перераспределять
struct bar{
std::vector<int> data;
};
std::vector<bar> foo(1);
foo.back().data.push_back(3);
foo.reserve(10); // two allocations and a delete occur in C++03
каждый раз , когда fooбуфер «s перераспределяется в C ++ 03 он копируется каждый vectorв bar.
В C ++ 11 вместо этого перемещается bar::datas, что в основном бесплатно.
В этом случае это зависит от оптимизации внутри stdконтейнера vector. В каждом случае ниже использование stdконтейнеров только потому, что они являются объектами C ++, которые имеют эффективную moveсемантику в C ++ 11 «автоматически» при обновлении компилятора. Объекты, которые не блокируют его и содержат stdконтейнер, также наследуют автоматически улучшенные moveконструкторы.
НРВО провал
Когда NRVO (оптимизация именованного возвращаемого значения) завершается неудачно, в C ++ 03 он возвращается к копии, а в C ++ 11 - к перемещению. Неудачи НРВО легки:
std::vector<int> foo(int count){
std::vector<int> v; // oops
if (count<=0) return std::vector<int>();
v.reserve(count);
for(int i=0;i<count;++i)
v.push_back(i);
return v;
}
или даже:
std::vector<int> foo(bool which) {
std::vector<int> a, b;
// do work, filling a and b, using the other for calculations
if (which)
return a;
else
return b;
}
У нас есть три значения - возвращаемое значение и два разных значения внутри функции. Elision позволяет объединять значения в функции с возвращаемым значением, но не друг с другом. Они оба не могут быть объединены с возвращаемым значением без объединения друг с другом.
Основная проблема заключается в том, что элиминация NRVO является хрупкой, и код с изменениями, не находящимися рядом с returnсайтом, может внезапно привести к значительному снижению производительности в этом месте без использования диагностической информации. В большинстве случаев сбоя NRVO C ++ 11 заканчивается moveкопией, а C ++ 03 заканчивается копией.
Возврат аргумента функции
Исключение также невозможно здесь:
std::set<int> func(std::set<int> in){
return in;
}
в C ++ 11 это дешево: в C ++ 03 нет способа избежать копирования. Аргументы функций не могут быть исключены с возвращаемым значением, потому что время жизни и местоположение параметра и возвращаемого значения управляются вызывающим кодом.
Тем не менее, C ++ 11 может переходить от одного к другому. (В менее игрушечном примере что-то может быть сделано с set).
push_back или insert
Наконец, исключение в контейнеры не происходит: но C ++ 11 перегружает rvalue, перемещает операторы вставки, что сохраняет копии.
struct whatever {
std::string data;
int count;
whatever( std::string d, int c ):data(d), count(c) {}
};
std::vector<whatever> v;
v.push_back( whatever("some long string goes here", 3) );
в C ++ 03 создается временный объект whatever, затем он копируется в вектор v. std::stringВыделено 2 буфера, каждый с одинаковыми данными, а один отбрасывается.
В C ++ 11 временный whateverсоздается. whatever&& push_backПерегрузки , то moveс , что временная в вектор v. Один std::stringбуфер выделяется и перемещается в вектор. Пустое std::stringотбрасывается.
присваивание
Украденный из ответа @ Jarod42 ниже.
Исключение не может произойти с назначением, но может произойти.
std::set<int> some_function();
std::set<int> some_value;
// code
some_value = some_function();
здесь some_functionвозвращает кандидата для исключения, но поскольку он не используется для непосредственного создания объекта, он не может быть исключен. В C ++ 03 вышеприведенное приводит к тому, что содержимое временного объекта копируется в some_value. В C ++ 11 он перемещен some_value, что в основном бесплатно.
Для полного эффекта вышеперечисленного вам нужен компилятор, который синтезирует конструкторы перемещения и присваивания для вас.
MSVC 2013 реализует конструкторы перемещения в stdконтейнерах, но не синтезирует конструкторы перемещения для ваших типов.
Таким образом, типы, содержащие std::vectors и подобные, не получат таких улучшений в MSVC2013, но начнут получать их в MSVC2015.
clang и gcc уже давно реализовали неявные конструкторы перемещения. Компилятор Intel 2013 года будет поддерживать неявную генерацию конструкторов перемещения, если вы пропустите -Qoption,cpp,--gen_move_operations(по умолчанию они этого не делают, пытаясь обеспечить кросс-совместимость с MSVC2013).