В C++ има концепция, наречена elision.
Elision взема два привидно различни обекта и обединява тяхната идентичност и живот.
Преди c++17 може да възникне елизия:
Когато имате непараметрична променлива Foo f;
във функция, която е върнала Foo
и изразът за връщане е просто return f;
.
Когато имате анонимен обект, който се използва за конструиране на почти всеки друг обект.
В c++17 всички (почти?) случаи на #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 стойност.
Другият известен случай се нарича оптимизиране на възвръщаемата стойност, NRVO. Това е (1) случай на елизия по-горе.
Foo func() {
Foo local;
return local;
}
Foo foo = func();
отново, elision може да обедини живота и идентичността на Foo local
, върнатата стойност от func
и Foo foo
извън func
.
Дори c++17, второто сливане (между върнатата стойност на func
и Foo foo
) не е задължително (и технически prvavalue, върнато от func
, никога не е обект, а просто израз, който след това е обвързан да конструира Foo foo
), но първото остава незадължително и изисква съществуването на конструктор за преместване или копиране.
Елисията е правило, което може да възникне дори ако елиминирането на тези копия, разрушения и конструкции би имало забележими странични ефекти; това не е оптимизация "като че ли". Вместо това, това е фина промяна от това, което един наивен човек може да си помисли, че кодът на 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
заедно не е законно и животът им се припокрива.
Все още можете да го направите под as-if, но само ако можете да разгледате и разберете всички странични ефекти на деструкторите, конструкторите и .futz()
.
person
Yakk - Adam Nevraumont
schedule
22.10.2018
return
, до C++14( !) формулировката заreturn
не казва, че локалните временни елементи са продължили достатъчно дълго, за да бъдат използвани при конструирането на върнатата стойност. - person Davis Herring   schedule 23.10.2018return std::move(pointer)
, но същоreturn pointer;
и работи без активна семантика на преместване, Copy elision е по някакъв начин оптимизация на семантиката на преместване сама по себе си, когато наистина не се нуждаете от темпорален обект. Той никога не е съществувал, така че не е имало допълнително придобиване на ресурси, така че няма какво да се унищожи. Единственият случай, когато вреди на RAII, е когато придобиването на ресурс се третира като собственост на интерфейса, което беше спорна точка за известно време. - person Swift - Friday Pie   schedule 23.10.2018*this
? Разбира се, dtors са свързани със страничните ефекти. - person curiousguy   schedule 24.10.2018