Не должно ли применяться гарантированное копирование? - PullRequest
0 голосов
/ 30 мая 2018

Я не понимаю поведение gcc здесь, я ожидаю, что RVO будет применяться, но независимо от того, передам ли я флаги оптимизации и / или я передам -std=c++17, во втором случае, кажется, что пара бесплатных фигурных скобок предотвращаетGCC от удаления копии.

$ cat /tmp/foo.cc
#include <iostream>
#define PING() std::cerr << __PRETTY_FUNCTION__ << '\n'

struct foo
{
  foo() { PING(); }
  ~foo() { PING(); }
  foo(const foo&) { PING(); }
};

foo bar()
{
  PING();
  foo res;
  return res;
}

foo baz()
{
  PING();
  {
    foo res;
    return res;
  }
}

int main()
{
  foo f1 = bar();
  foo f2 = baz();
}
$ g++-mp-7 -std=c++17 -O3 foo.cc
$ ./a.out
foo bar()
foo::foo()
foo baz()
foo::foo()
foo::foo(const foo&)
foo::~foo()
foo::~foo()
foo::~foo()

Разве это не должно быть частью гарантированного исключения копии?Поведение Clang соответствует моим ожиданиям:

$ clang++-mp-4.0 foo.cc
$ ./a.out
foo bar()
foo::foo()
foo baz()
foo::foo()
foo::~foo()
foo::~foo()

Ответы [ 2 ]

0 голосов
/ 30 мая 2018

С https://en.cppreference.com/w/cpp/language/copy_elision

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

  • Если функция возвращает тип класса по значению, а выражением оператора return является имя энергонезависимого объекта с автоматической продолжительностью хранения, который не является параметром функции или параметром предложения catch, икоторый имеет тот же тип (игнорируя cv-квалификацию верхнего уровня), что и тип возвращаемого значения функции, затем копирование / перемещение (начиная с C ++ 11) опускается.Когда этот локальный объект создается, он создается непосредственно в хранилище, куда возвращаемое значение функции в противном случае было бы перемещено или скопировано.Этот вариант удаления копии известен как NRVO, «именованная оптимизация возвращаемого значения».

Не гарантируется, что NRVO произойдет, но это возможно в вашем случае.

Как отметил Сандер Де Дайкер в комментарии, уже есть сообщение об ошибке , чтобы получить такую ​​возможность.

0 голосов
/ 30 мая 2018

RVO (оптимизация возвращаемого значения) применяется только при возврате временного из функции.И в bar, и в baz вы не возвращаете временный.Вместо этого вы возвращаете объект с именем .Это означает, что вы имеете дело с NRVO (оптимизация именованного возвращаемого значения), и это не гарантировано и труднее сделать.Оба выхода соответствуют стандарту, и только clang выполняет оптимизацию лучше, чем gcc.

...