В C ++ существует понятие, называемое elision.
Elision берет два, казалось бы, различных объекта и объединяет их идентичность и время жизни.
До c ++ 17 elisionможет произойти:
Если у вас есть непараметрическая переменная Foo f;
в функции, которая возвратила Foo
, а оператор возврата был простым return f;
.
Когда у вас есть анонимный объект, используемый для создания практически любого другого объекта.
In c ++ 17 all (почти?)) случаи № 2 устраняются новыми правилами prvalue;elision больше не происходит, потому что то, что раньше использовалось для создания временного объекта, больше не происходит.Вместо этого конструкция «временного» напрямую связана с постоянным местоположением объекта.
Теперь, elision не всегда возможен, учитывая ABI, в который компилируется компилятор.Два общих случая, когда это возможно, известны как Оптимизация возвращаемого значения и Оптимизация именованного возвращаемого значения.
RVO имеет такой случай:
Foo func() {
return Foo(7);
}
Foo foo = func();
, где у нас есть возвращаемое значение Foo(7)
которое опускается в возвращаемое значение, которое затем опускается во внешнюю переменную foo
.То, что кажется 3 объектами (возвращаемое значение foo()
, значение в строке return
и Foo foo
), фактически равно 1 во время выполнения.
До c ++ 17 здесь должны существовать конструкторы копирования / перемещения, а elision является необязательным;в c ++ 17 из-за новых правил prvalue не требуется конструктор копирования / перемещения, и для компилятора нет опций, здесь должно быть значение 1.
Другой известныйcase называется возвращаемым значением оптимизации, NRVO.Это (1) случай elision выше.
Foo func() {
Foo local;
return local;
}
Foo foo = func();
снова, elision может объединить время жизни и идентичность Foo local
, возвращаемое значение от func
и Foo foo
вне func
.
Даже c ++ 17 , второе слияние (между возвращаемым значением func
и Foo foo
) не является обязательным (и технически значение, возвращаемое из func
).никогда не является объектом, просто выражением, которое затем связывается для построения Foo foo
), но первое остается необязательным и требует наличия конструктора перемещения или копирования.
Elision - это правило, которое может произойти дажеесли устранение этих копий, разрушения и конструкции будут иметь заметные побочные эффекты;это не оптимизация "как будто".Вместо этого это тонкое изменение по сравнению с тем, что наивный человек может думать, что означает код C ++.Называть его «оптимизацией» - это не просто неправильное название.
Тот факт, что он является необязательным, и что тонкие вещи могут его сломать, является проблемой с ним.
Foo func(bool b) {
Foo long_lived;
long_lived.futz();
if (b)
{
Foo short_lived;
return short_lived;
}
return long_lived;
}
в вышеприведенном случае, хотя компилятору разрешено исключать как Foo long_lived
, так и Foo short_lived
, проблемы реализации делают его в принципе невозможным, поскольку оба объекта не могут объединить свои времена жизни с возвращаемым значением func
;одновременное исключение short_lived
и long_lived
недопустимо, и время их жизни перекрывается.
Вы все еще можете делать это как если бы, но только если вы можете исследовать и понять все побочные эффекты деструкторов, конструкторов и.futz()
.