Как я могу быть уверен, что процедура использует преимущества (N) RVO?
-
09-12-2019 - |
Вопрос
Я хотел бы убедиться, что мои процедуры используют (N) RVO, когда это возможно.Помимо синтаксического анализа результирующей дизассембляции, есть ли что-то, что я могу сделать или проверить, компилируется ли процедура с (N) RVO?На данный момент меня больше всего интересуют MSVC и GCC.
Решение
Нет, не совсем.
Однако вы можете следовать рекомендациям при написании своего кода.
Оптимизация Безымянного возвращаемого значения
Это в значительной степени срабатывает каждый раз, когда вы возвращаете временное значение, даже в режиме отладки.
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
сам по себе.
Если вы будете следовать этому, то увеличите шансы в свою пользу.И тогда это всего лишь вопрос проверки кода.
И вы также облегчаете чтение своего кода, поскольку не объявляете переменные до того, как узнаете, что они вам действительно нужны!
Другие советы
Вы можете добавить методы отладки в деструктор:
struct A
{
~A() { cout << "destructor called"; }
};
A foo()
{
A a;
return a;
}
.
Если вызывается деструктор, RVO, вероятно, не был применен.
Возможные способы думать:
-
Реализация механизма подсчета ссылок в вашем классе, который отслеживает количество экземпляров, созданных через класс, что-то в значительной степени похоже на генеракодицетагкод, таким образом, вы можете обнаружить дополнительные копии вашего класса, созданного и удаленного, еслиCopy Enision не происходит.
-
Вы могли бы просто поставить следы отладки в Copy Constructor и Destructor для вашего класса, если выяснение копирования не происходит, вы увидите много преследующих преследующих копий и отладки.