Если оптимизация не требует затрат, сделайте это. При написании кода ++i
так же легко написать, как и i++
, поэтому предпочитайте первый. Там нет никаких затрат.
С другой стороны, возвращение и внесение этого изменения впоследствии требует времени, и, скорее всего, оно не будет иметь заметного значения, поэтому вам, вероятно, не стоит беспокоиться.
Но да, это может иметь значение. На встроенных типах, вероятно, нет, но для сложных классов компилятор вряд ли сможет его оптимизировать. Причина этого заключается в том, что операция инкремента больше не является встроенной операцией, встроенной в компилятор, а является функцией, определенной в классе. Компилятор может оптимизировать его, как и любую другую функцию, но, в общем, он не может предположить, что вместо постинкремента можно использовать предварительное увеличение. Эти две функции могут делать совершенно разные вещи.
Таким образом, при определении того, какие оптимизации могут быть выполнены компилятором, подумайте, достаточно ли у него информации для его выполнения. В этом случае компилятор не знает, что постинкремент и преинкремент выполняют одинаковые изменения объекта, поэтому он не может предположить, что один из них может быть заменен другим. Но у вас есть это знание, поэтому вы можете безопасно выполнить оптимизацию.
Многие другие, о которых вы упомянули, обычно могут быть выполнены компилятором очень эффективно:
Встраивание может быть сделано компилятором, и обычно оно лучше, чем у вас. Все, что нужно знать, - это то, насколько большая часть функции состоит из вызова функции над головой и как часто она вызывается? Большая функция, которая часто вызывается, вероятно, не должна быть встроенной, потому что в итоге вы копируете много кода, что приводит к увеличению размера исполняемого файла и большему количеству пропусков кэша инструкций. Встраивание всегда компромисс, и часто компилятор лучше взвешивает все факторы, чем вы.
Развертывание цикла - чисто механическая операция, и компилятор может легко это сделать. То же самое касается снижения прочности. Поменять местами внутренние и внешние циклы сложнее, потому что компилятор должен доказать, что измененный порядок обхода не повлияет на результат, что сложно сделать автоматически. Итак, вот оптимизация, которую вы должны сделать сами.
Но даже в простых, которые способен сделать компилятор, у вас иногда есть информация, которой нет у вашего компилятора. Если вы знаете, что функция будет вызываться очень часто, даже если она вызывается только из одного места, возможно, стоит проверить, автоматически ли встроен компилятор, и, если нет, сделать это вручную.
Иногда вы можете знать больше о цикле, чем о компиляторе (например, что число итераций всегда будет кратно 4, поэтому вы можете безопасно развернуть его 4 раза). Компилятор может не иметь этой информации, поэтому, если бы он был встроен в цикл, ему пришлось бы вставить эпилог, чтобы гарантировать, что последние несколько итераций будут выполнены правильно.
Таким образом, такие «мелкомасштабные» оптимизации все еще могут быть необходимы, если 1) вам действительно нужна производительность, и 2) у вас есть информация, которой нет у компилятора.
Вы не можете превзойти компилятор по чисто механическим оптимизациям. Но вы можете предположить, что компилятор не может этого сделать, и , что - это когда вы можете оптимизировать лучше, чем компилятор.