Копируется объект или нет, когда срабатывает RVO/NRVO?

Я не могу понять определение RVO (и NRVO) из-за множества вопросов, подобных этому, которые мне кажутся предполагающими что RVO опускает конструктор копирования. Теперь согласно 12.8.15

В таких случаях реализация рассматривает источник и цель пропущенной операции копирования просто как два разных способа обращения к одному и тому же объекту, и уничтожение этого объекта происходит в более позднее время, когда два объекта были бы уничтожены без оптимизация.

Похоже, что опущен не вызов конструктора копирования, а сама копия - просто объект создается в месте «копии» в первую очередь, и поэтому нет «исходного» объекта и вообще нет копирования. Таким образом, даже если у класса есть конструктор копирования private, он может быть возвращен из функции, когда срабатывает RVO, потому что копии нет.

Я правильно понимаю? Опущено ли само копирование или опущен вызов конструктора копирования? Должен ли быть разрешен возврат объекта из функции, когда класс объекта имеет частный конструктор копии?


person sharptooth    schedule 24.04.2012    source источник


Ответы (6)


Официально нет, RVO/NRVO не влияет на то, хорошо ли сформирована программа. Стандарт явно разрешает опускать любые побочные эффекты конструктора копирования, но проверка доступа к конструктору копирования по-прежнему предполагается.

Однако большинство компиляторов не будет проверять доступ к пропущенным конструкторам копирования, если вы не попросите, чтобы правила применялись как можно более строго. Я не совсем уверен, но, кажется, я использовал несколько, которые пропускали проверку доступа, даже когда вы действительно требовали строгого соблюдения (но я не помню точно).

Изменить (чтобы исправить то, что я вижу как неправильное представление, выраженное в некоторых других ответах):

Параграфы в разделе стандарта предназначены для чтения по порядку. Требования в первом абзаце, применимые к ситуации, применяются всегда. В данном случае разрешение опустить побочные эффекты находится в пункте 15. Однако непосредственно перед этим в пункте 14 мы видим, что:

Программа является неправильно сформированной, если конструктор копирования или оператор присваивания копии для объекта используются неявно, а специальная функция-член недоступна (раздел 11).

Итак, мы попадаем в пункт 15 (где копирование можно опустить) только если проверка доступа, указанная в пункте 14, уже пройдена.

person Jerry Coffin    schedule 24.04.2012

Копирование опускается, если оптимизация вступает в силу, но компилятор по-прежнему должен проверять доступность конструктора копирования. В противном случае код будет недействительным, если компилятор (или какой-либо другой компилятор) решит не оптимизировать.

person Bo Persson    schedule 24.04.2012

Пропущено ли само копирование или вызов конструктора копирования?

Сама операция копирования опущена. Если вы посмотрите на полную цитату, в ней четко указано:

C++ 03 12.8 копирование объектов класса

Параграф 15

При соблюдении определенных критериев реализации разрешается пропускать конструкцию копирования объекта класса, даже если конструктор копирования и/или деструктор объекта имеют побочные эффекты. В таких случаях реализация рассматривает источник и цель пропущенной операции копирования просто как два разных способа обращения к одному и тому же объекту, и уничтожение этого объекта происходит в более поздний момент времени, когда два объекта были бы уничтожены. уничтожается без оптимизации. 111) Это исключение операций копирования разрешено в следующих обстоятельствах (которые могут быть объединены для устранения нескольких копий):

— в операторе return в функции с возвращаемым типом класса, когда выражение является именем энергонезависимого автоматического объекта с тем же типом cv-unqualified, что и возвращаемый тип функции, операция копирования может быть опущена< /strong> путем создания автоматического объекта непосредственно в возвращаемом функцией значении.

— когда временный объект класса, который не был привязан к ссылке (12.2), будет скопирован в объект класса с тем же типом cv-unqualified, операция копирования может быть опущена путем создания временного объекта прямо в цель пропущенной копии.....

Должен ли быть разрешен возврат объекта из функции, если класс объекта имеет закрытый конструктор копирования?

RVO и NRVO — это оптимизации компилятора, разрешенные компилятором, но не гарантированные. Что произойдет, если какой-то конкретный глупый компилятор не сможет обеспечить эти оптимизации?
Без доступного конструктора копирования код будет ломаться на всех таких компиляторах, которые нежелательно. Учитывая, что конструктор копирования должен быть доступен.

person Alok Save    schedule 24.04.2012

Сама копия опущена. Всякий раз, когда копирование действительно выполняется, оно должно выполняться с помощью конструктора копирования, но есть несколько случаев, когда компилятору разрешено оптимизировать копию.

Стек возвращает более крупные и неподовые объекты. Вызывающий объект подготавливает пространство для объекта и передает указатель на это пространство в качестве скрытого параметра. Вызываемый затем копирует объект в это пространство. Здесь можно сделать две оптимизации:

  1. Вызываемый объект может создать объект непосредственно в пространстве возврата. Компилятор должен быть уверен, что объект будет возвращен, то есть могут следовать только операторы return, возвращающие этот объект, и промежуточный код не должен вызывать выброс.
  2. Если результат присваивается переменной, вызывающая сторона может передать ее адрес вместо создания временного. Это можно сделать только в том случае, если переменная либо инициализируется, либо если эффект не будет отличаться от вызова operator=, что в основном происходит, если тип имеет конструктор по умолчанию, деструктор и operator=.
person Jan Hudec    schedule 24.04.2012

Опущено ли само копирование или опущен вызов конструктора копирования?

Идея состоит в том, что конструктор копирования опущен, хотя компилятору разрешено совместно использовать память, если это не меняет семантику программы.

Должен ли быть разрешен возврат объекта из функции, когда класс объекта имеет частный конструктор копии?

Нет, это не разрешено. «Должно ли это быть» трудно сказать, но разрешение этого позволит вам совершать всевозможные махинации и нарушать инкапсуляцию. В С++ 11 вы можете сделать это, используя конструкцию {} в возврате и переместить, создав это значение.

person Pubby    schedule 24.04.2012
comment
-1: Вводит в заблуждение. Это копия, которая опущена. Копирование всегда должно выполняться с помощью конструктора копирования, иначе весь ад вырвется наружу. Легко сказать, что должен, нет, не должен, потому что компилятору не нужно оптимизировать копию, поэтому это должно быть возможно сделать. - person Jan Hudec; 24.04.2012

Если вы посмотрите на эту статью, NRVO обнаружен в MSDN

Вы увидите, что соинструктор по копированию не вызывался.

person Denis Ermolin    schedule 24.04.2012