Почему g ++ не включает RVO здесь? - PullRequest
1 голос
/ 15 февраля 2012

Считайте, что ТЕСТ-код:

#include <iostream>
using namespace std;

class Klass
{
public:
  Klass()
  {
    cout << "Klass()" << endl;
  }

  Klass(const Klass& right)
  {
    cout << "Klass(const Klass& right)" << endl;
  }
};

Klass create(Klass a)
{
  cout << "create(Klass a)" << endl;
  return a;
}

int main()
{
  const Klass result = create(Klass());
}

Компиляция с:

g++ -O3 rvo.cpp   -o rvo

Вывод:

$ ./rvo
Klass()
create(Klass a)
Klass(const Klass& right)

Я ожидал, что компилятор будет использовать механизм RVO, чтобы исключить каждый вызов COPY CTOR, чтобы избежать копирования возвращаемого значения И параметра функции create(). Почему это не так?

Ответы [ 2 ]

3 голосов
/ 15 февраля 2012

Стандарт разрешает копирование только в том случае, если вы передаете временное значение в качестве аргумента функции.

Два ожидаемых вами решения выделены жирным шрифтом ниже:

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

  • в операторе возврата в функции с типом возврата класса, когда выражением является имя энергонезависимого автоматического объекта (, отличного от параметра функции или оператора catch * ) с тот же cv-неквалифицированный тип, что и тип возврата функции, операция копирования / перемещения может быть опущена путем создания автоматического объекта непосредственно в возвращаемое значение функции
  • в выражении throw, когда операндом является имя энергонезависимого автоматического объекта (отличного от параметра функции или предложения catch), область которого не выходит за пределы самого внутреннего включающего блока try (если существует один), операция копирования / перемещения из операнда в объект исключения (15.1) может быть опущена путем создания автоматического объекта непосредственно в объект исключения
  • когда временный объект класса, который не был привязан к ссылке (12.2), будет скопирован / перемещен в объект класса с таким же типом cv-unqualified, операция копирования / перемещения может быть опущена путем создания временный объект непосредственно в цель пропущенного копирования / перемещения
  • когда объявление-исключение обработчика исключений (раздел 15) объявляет объект того же типа (за исключением cv-квалификации), что и объект исключения (15.1), операция копирования / перемещения может быть опущена путем обработки исключения -объявление в качестве псевдонима для объекта исключения, если значение программы не изменится, за исключением выполнения конструкторов и деструкторов для объекта, объявленного объявлением исключения. [..]

Это не произошло для возвращаемого значения, потому что энергонезависимое имя было параметром функции.

Это произошло произошло для конструкции в параметре create, в противном случае вы бы увидели:

Klass()
Klass(const Klass& right)
create(Klass a)
Klass(const Klass& right)
2 голосов
/ 15 февраля 2012

Копия, которую вы видите, является копией оператора return в функции create.Это не может быть устранено с помощью RVO, так как невозможно создать возвращаемое значение напрямую.Вы просили «вернуть».Копия нужна здесь;нет способа вернуть объект без него.

На стандартном языке следующее условие [C ++ 11: 12.8 / 31] не выполняется

при возвратеоператор в функции с типом возвращаемого класса, когда выражением является именем энергонезависимого автоматического объекта (, отличного от функции или catch-clause параметр ) с тем же типом cv-unqualified, что и тип возвращаемого функцией, операция копирования / перемещения может быть опущена путем создания автоматического объекта непосредственно в возвращаемое значение функции

Asпо причинам, это не произвольное правило, оно имеет смысл с точки зрения реализации, поскольку это то, что невозможно сделать с параметрами функции:

построение автоматического объекта непосредственно ввозвращаемое значение функции

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

...