Может копировать 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;
}
Другие вопросы по тегам