c ++ производительность возврата примитива по значению или по (const) ссылке - PullRequest
2 голосов
/ 12 ноября 2010

Допустим, следующий класс игрушек и современные компиляторы (например, последние gcc).

template <typename T>
class SomeVec {
public:
  ...
  virtual T get(const int index) = 0;
}

Приложение включает в себя значительное количество сокращений чисел на основе значений, хранящихся в подклассах SomeVec, причем T является примитивным типом, скажем, int. Однако практика stl containers и boost::numeric::ublas::vector - возвращать сохраненные значения через (const) reference.

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

Теперь мои вопросы:

  • (1) stl и ublas являются шаблонами, в то время как мое решение требует виртуальных методов. Это мешает современным компиляторам оптимизировать код?

  • (2) Если компилятор не смог оптимизировать для возврата атомарной ссылки const в качестве значения, то правильно ли я полагаю, что вызов виртуального метода и стоимость разыменования примерно одинаковы? Или один значительно дороже другого?

Спасибо!

Ответы [ 2 ]

3 голосов
/ 12 ноября 2010

Причина, по которой STL возвращает ссылки, состоит в том, что шаблонный код не может позволить себе роскошь знать, что возвращаемые объекты малы.Хотя int не проблема, возвращение большой структуры замедляет процесс без веской причины.В последнем случае имеет смысл использовать ссылки, и поскольку разумный компилятор может оптимизировать случай использования примитивных типов, вы также можете использовать ссылки повсюду.

Обратите внимание, что ваш метод virtual T get(const int index) отличается другими способами.к контейнерным методам STL.Что наиболее важно и связано с вышеупомянутой проблемой, ваш метод возвращает копию индексированного объекта: манипулирование результатом не изменит состояния объекта в вашем контейнере.

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

Наконец, действительно ли вы уверены, что ваш класс должен бытьдинамически полиморфный (т.е. есть виртуальные методы)?Контейнеры STL специально предназначены для того, чтобы не наследоваться (поэтому у них нет virtual деструкторов).Контейнеры не предназначены для обеспечения интерфейса для производных классов, скорее они существуют для облегчения реализации.Я бы сказал, что предлагаемые вами примеры подклассов могут быть так же легко реализованы, как и классы-обертки вокруг шаблонного контейнера, предпочитая повторное использование кода через композицию, а не наследование (что, среди прочего, поддерживает Gang of Four ).Помимо хорошей практики, избегание использования virtual методов избавляет от наличия vtables и соответствующих указателей в ваших объектах и ​​требует дополнительного поиска vtable в каждом вызове.Если вам действительно не нужен динамический полиморфизм, зачем брать цену (и, возможно, предотвращать оптимизацию компилятора)?

2 голосов
/ 12 ноября 2010

Необычно иметь виртуальную функцию в классе шаблона.Если функция не виртуальная, компилятор обычно вставляет код в код и оптимизирует разницу между возвратом по ссылке и возвратом по значению до нуля.

Компилятор может по-прежнему встроить функцию, если он не 't вызывается через указатель или ссылку - компилятор будет знать точную функцию-член, которая должна быть вызвана в этом случае, и ему не нужно будет искать ее через vtable.

Стоимость ссылки будетмаленький, просто разыменованиеЭто может быть даже не целая инструкция на уровне сборки.

...