Стандарт не требует, чтобы компилятор выполнял оптимизацию возвращаемого значения (RVO), но затем, начиная с C ++ 11, результат должен быть перемещен .
Похоже, что это может ввести код UB to / break, который был действителен в C ++ 98.
Например:
#include <vector>
#include <iostream>
typedef std::vector<int> Vec;
struct Manager{
Vec& vec;
Manager(Vec& vec_): vec(vec_){}
~Manager(){
//vec[0]=42; for UB
vec.at(0)=42;
}
};
Vec create(){
Vec a(1,21);
Manager m(a);
return a;
}
int main(){
std::cout<<create().at(0)<<std::endl;
}
При компиляции с gcc (или в этом случае clang) с -O2 -fno-inline -fno-elide-constructors
(я использую std::vector
с этими опциями сборки, чтобы упростить пример. Можно было бы вызвать то же поведение без этих опций с помощью handmade -классы и более сложная create
-функция) все в порядке для C ++ 98 (-std=c++98
):
return a;
запускает конструктор копирования, который оставляет a
нетронутым.
- Вызывается деструктор
m
(должен произойти до разрушения a
, потому что m
создается после a
). Доступ к a
в деструкторе не вызывает затруднений.
- Деструктор
a
называется.
Результат, как и ожидалось: 21
напечатано ( здесь в прямом эфире ).
Ситуация, однако, отличается при сборке в C ++ 11 (-std=c++11
):
return a;
запускает конструктор движения, который "уничтожает" a
.
- Вызывается деструктор
m
, но теперь доступ к a
проблематичен, поскольку a
был перемещен и больше не поврежден.
vec.at(0)
бросков сейчас.
Вот живая демонстрация .
Я что-то упустил, и пример проблематичен и в C ++ 98?