У меня есть следующие две функции:
Class foo(Class arg)
{
return arg;
}
Class bar(Class *arg)
{
return *arg;
}
Теперь, когда я вызываю только foo (arg), конструктор копирования, конечно, вызывается дважды. Когда я звоню в бар (&arg) только он вызывается только один раз. Таким образом, я бы ожидал
foo(bar(&arg));
конструктор копирования вызывается здесь три раза. Однако, это все еще только вызвано дважды. Это почему? Компилятор распознает, что другая копия не нужна?
Заранее спасибо!
Компилятор распознает, что другая копия не нужна?
Это действительно так. Компилятор выполняет копирование / перемещение. Это единственное исключение из так называемого правила «как если бы», и оно позволяет компилятору (при некоторых обстоятельствах, например, как в вашем примере) исключать обращения к конструктору копирования или перемещения класса, даже если они имеют сторону последствия.
В соответствии с пунктом 12.8 / 31 стандарта C ++ 11:
При соблюдении определенных критериев реализация может опустить конструкцию копирования / перемещения класса.
объект, даже если выбран конструктор для операции копирования / перемещения и / или деструктор для объекта
имеют побочные эффекты. В таких случаях реализация обрабатывает источник и цель пропущенного копирования / перемещения.
операция, как просто два разных способа обращения к одному и тому же объекту, и уничтожение этого объекта
происходит в более поздние времена, когда два объекта были бы уничтожены без оптимизации.
Это исключение операций копирования / перемещения, называемых копия elision, допускается при следующих обстоятельствах (которые
могут быть объединены для устранения нескольких копий):— в
return
оператор в функции с типом возвращаемого класса, когда выражение является именем
энергонезависимый автоматический объект (отличный от параметра функции или оператора catch) с тем же cv-unqualified
type в качестве типа возврата функции, операция копирования / перемещения может быть опущена путем конструирования
автоматический объект непосредственно в возвращаемое значение функции— […]
— когда будет скопирован / перемещен временный объект класса, который не был связан со ссылкой (12.2)
для объекта класса с таким же cv-неквалифицированным типом, операция копирования / перемещения может быть опущена
построение временного объекта непосредственно в цель пропущенного копирования / перемещения— […]
С GCC вы можете попробовать использовать -fno-elide-constructor
флаг компиляции, чтобы подавить эту оптимизацию и посмотреть, как будет вести себя компилятор, когда не происходит исключения копирования.
Других решений пока нет …