Стандарт не требует, чтобы компилятор выполнял оптимизацию возвращаемого значения (RVO), но тогда, начиная с C++11, результат должен быть перемещен.
Похоже, что это может ввести код UB для/разрыва, который был действителен в 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
с этой опцией сборки, чтобы упростить пример. Можно было бы вызвать такое же поведение без этих опций с классами ручной работы и более сложным create
-функция) для C++98(-std=c++98
) все в порядке:
return a;
запускает конструктор копирования, который оставляетa
нетронутым.- Вызывается деструктор
m
(должен произойти до уничтоженияa
, потому чтоm
создается послеa
). Доступ кa
в деструкторе не проблематичен. - Вызывается деструктор
a
.
Результат ожидаемый: печатается 21
(здесь).
Однако ситуация отличается при сборке как С++ 11 (-std=c++11
):
return a;
запускает конструктор перемещения, который "уничтожает"a
.- Вызывается деструктор
m
, но теперь доступ кa
проблематичен, потому чтоa
был перемещен и больше не цел. vec.at(0)
бросает сейчас.
Вот живая демонстрация.
Я что-то упустил, и пример проблематичен и в С++ 98?
Vec a;
переживетManager m;
. - person Quimby   schedule 24.04.2019-fno-elide-constructors
исключает оптимизацию возвращаемого значения и вместо этого использует перемещение. Почему вы используете этот флаг? - person Maxim Egorushkin   schedule 24.04.2019a
не перемещен и цел. Независимо от того, выполняется ли RVO или нет, зависит от компилятора, поэтому можно не выполнять RVO (или я мог бы придумать более сложную функцию, для которой компилятор не выполняет RVO, но я хотел, чтобы она была простой) - person ead   schedule 24.04.2019a
все еще находится в допустимом состоянии после перемещения. - person Quimby   schedule 24.04.2019-fno-elide-constructors
, это подсказка - person Marek R   schedule 24.04.2019-fno-elide-constructors
, чтобы упростить пример, дело в том, что компилятор не использует RVO (что действительно) - person ead   schedule 24.04.2019int decltype = 1;
. Он действителен в C++03, но недействителен в C++11. - person Daniel Langr   schedule 24.04.2019overload resolution to select the constructor for the copy or the return_value overload to call is first performed as if the object were designated by an rvalue
, так как он должен использовать конструктор перемещения. Но моей отправной точкой был этот ответ: stackoverflow.com/a/17473874/5769463, который может быть не на 100% правильным. - person ead   schedule 24.04.2019-fno-elide-constructors
или без нее. В версии C++11 временное создается с семантикойmove
. - person jszpilewski   schedule 24.04.2019