Может копировать elision/RVO, вызывать копирование / перемещение с одного и того же объекта
Допустим, у меня есть функция, которая выглядит так:
SomeObject copy_maybe(bool make_new, const SomeObject& def)
{
if (make_new)
return SomeObject();
else
return def;
}
И я называю это так:
SomeObject obj;
obj = copy_maybe(true, obj);
Без разрешения копирования это, несомненно, всегда приведет к копированию в obj
из временного, созданного в copy_maybe
, Тем не менее, с копией elision/RVO, возможно ли, что копия произойдет из obj
в obj
?
Более конкретно, в этих (или аналогичных) условиях это возможно в операторе копирования (void operator=(SomeObject const &other)
) тот this
а также &other
будет так же из-за копирования elision?
Я создал тест на Ideone, и он возвращает отдельные адреса, но я просто хочу убедиться, что это поведение определяется спецификацией.
3 ответа
Тем не менее, с копией elision/RVO, возможно ли, что копия произойдет из
obj
вobj
?
Нет. Копия elison/RVO используется в процессе инициализации переменной. Так как вы уже инициализированы obj
с помощью SomeObject obj;
Вы не получите никакой оптимизации. Будет вызван оператор присвоения копии и obj
с сайта вызова будет присвоено значение obj
из функции.
Если у тебя есть
SomeObject obj = copy_maybe(true, obj);
Тогда да, копия elison может (будет в C++17) вступать в игру.
Обратите внимание, что звонки
SomeObject obj = copy_maybe(false, obj);
Покинет obj
в неопределенном состоянии, как это было бы так же, как
SomeObject obj = obj;
Копирование / перемещение назначений никогда не может быть отменено; исключение происходит только при инициализации объекта.
Тем не менее, есть способ применить elision к существующему объекту:
SomeObject obj;
new(&obj) auto(copy_maybe(false, obj);
C++ 17 определяет это интересным образом. Размещение new
происходит до строительства нового объекта. Размещение new
говорят, что "получить хранилище" для этого объекта.
И стандарт говорит, что когда вы "получаете хранилище" для объекта, время жизни любых объектов, которые уже находятся в этом хранилище, прекращается (так как их хранилище повторно используется для нового объекта). Следовательно, первоначально объявленному объекту истек срок его службы. Но это деструктор не вызывается; если ваша программа использует деструктор, вызываемый до окончания срока службы объекта, то у вас есть UB.
Но это все равно провоцирует UB. Зачем? Так как obj
жизнь закончилась раньше copy_maybe
называется. Так copy_maybe
получит ссылку на объект, который больше не существует. И когда copy_maybe
Получив доступ к ссылке на несуществующий объект, вы получите UB.
Так же:
SomeObject obj = copy_maybe(false, obj);
Это также провоцирует UB. Инициализация obj
невакуумный; следовательно, его время жизни не начинается, пока его инициализация не будет завершена. И это происходит в copy_maybe
, Но copy_maybe
дается ссылка на объект, у которого не было начала жизни. Это UB.
Тем не менее, с копией elision/RVO, возможно ли, что копия произойдет из
obj
вobj
?
Нет, чтобы "скопировать elision/RVO".
Да, чтобы "копия будет происходить из obj
в obj
"но только как копирование.
Рекомендуется проверять самостоятельное назначение в пользовательских функциях копирования. Когда вы это сделаете, ваш код должен работать нормально.
SomeObject& operator=(SomeObject const& rhs)
{
// Do nothing for self assignment.
if ( this != &rhs )
{
...
}
return *this;
}