Как я могу быть уверен, что рутина использует (N) RVO? - PullRequest
5 голосов
/ 08 марта 2012

Я хотел бы убедиться, что мои процедуры используют (N) RVO всякий раз, когда это возможно. Кроме анализа полученной разборки, могу ли я что-то сделать или проверить, чтобы увидеть, компилируется ли подпрограмма с (N) RVO? На данный момент меня больше всего интересуют MSVC и GCC.

Ответы [ 3 ]

7 голосов
/ 08 марта 2012

Нет, не совсем.

Однако при написании кода вы можете следовать рекомендациям.


Безымянная оптимизация возвращаемого значения

Этосрабатывает каждый раз, когда вы возвращаете временный объект, даже в режиме отладки.

return MyObject(....);

Оптимизация именованного возвращаемого значения

Это срабатывает практически каждый развремя, когда функция всегда возвращает один и тот же временный объект:

MyObject func() {
  MyObject result;
  if (...) { return result; }

  result.push(0);
  return result;
}

Вы можете смешивать их, но компилятору практически невозможно применить RVO в этом случае:

MyObject func() {
  MyObject result;
  if (...) { return MyObject(...); }

  return result;
}

Здесь,вероятно, что одно возвращение получит выгоду от RVO, а другое - нет.И я бы поспорил на первую оптимизируемую, потому что вы застряли бы, если бы вы спекулятивно создали result в обратном слоте и вдруг захотели взять ветку if.Обратите внимание, что просто переупорядочение операторов просто работает:

MyObject func() {
  if (...) { return MyObject(...); }

  MyObject result;

  return result;
}

Таким образом, практическое правило для NRVO заключается в том, что не должно быть оператора return между объявлением result и оператором return result;, которые возвращаютчто-нибудь еще, кроме result.


Если вы будете следовать этому, вы сложите шансы в свою пользу.И тогда это просто вопрос проверки кода.

И вы также облегчаете чтение своего кода, поскольку не объявляете переменные до того, как узнаете, что они действительно вам нужны!

2 голосов
/ 08 марта 2012

Вы можете добавить методы отладки в деструктор:

struct A
{
   ~A() { cout << "destructor called"; }
};

A foo()
{
   A a;
   return a;
}

Если вызывается деструктор, RVO, вероятно, не применялся.

1 голос
/ 08 марта 2012

Возможные варианты:

  1. Реализация механизма подсчета ссылок в вашем классе, который отслеживает количество экземпляров, созданных с помощью класса, что-то очень похожее на shared_ptr, таким образом, вы можете обнаружить дополнительные копии создаваемого класса и удаляется, если удаление не происходит.

  2. Вы можете просто поместить трассировки отладки в конструктор копирования и деструктор для своего класса, если исключение копирования не происходит, вы увидите много последовательных трассировок конструктора копирования и деструктора.

...