Почему в C ++ нет стандартного способа форсирования? - PullRequest
20 голосов
/ 24 мая 2011

Согласно статье в Википедии C ++

C ++ предназначен для предоставления программисту выбора, даже если это дает возможность программисту сделать неправильный выбор.

Если он спроектирован таким образом, почему нет стандартного способа заставить компилятор что-то встроить, даже если я могу ошибаться?

Или я могу спросить, почему ключевое слово inline является простонамек?

Я думаю, что у меня нет здесь выбора.

В мире ООП мы вызываем методы для объектов, и прямого доступа к членам следует избегать.Если мы не можем заставить методы доступа быть встроенными, то мы не сможем написать высокопроизводительные, но все еще поддерживаемые приложения.

(я знаю, что многие компиляторы реализуют свой собственный способ принудительного встраивания, но это уродливо.сделать так, чтобы встроенные средства доступа к классу тоже были ужасны.)

Всегда ли компилятор делает это лучше, чем программист?

Ответы [ 5 ]

18 голосов
/ 24 мая 2011

Как компилятор встроит рекурсивную функцию (особенно, если компилятор не поддерживает оптимизацию вызовов Tail, и даже если это так, функция не поддерживает оптимизацию вызовов Tail).

Это только одна из причин, по которой компилятор должен решить, практичен он-лайн или нет. Могут быть и другие, о которых я не могу думать прямо сейчас.

5 голосов
/ 24 мая 2011

Всегда ли компилятор делает это лучше, чем программист?

Нет, не всегда ... но программист гораздо более подвержен ошибкам и менее склонен поддерживать оптимальную настройкув течение нескольких лет.Суть в том, что встраивание помогает повысить производительность только в том случае, если функция действительно мала (хотя бы для одного общего / важного пути кода), но затем может помочь примерно на порядок, в зависимости от многих вещей, конечно.Программисту часто нецелесообразно оценивать, не говоря уже о том, чтобы тщательно следить за тем, насколько тривиальной является функция, и пороговые значения могут варьироваться в зависимости от выбора реализации компилятора, параметров командной строки, модели ЦП и т. Д.функция - любой не встроенный тип может запускать все виды различного поведения (особенно в шаблонах), использование оператора (даже new) может быть перегружено, многословие соглашений о вызовах и этапов обработки исключений обычно не очевидно дляпрограммист.

Скорее всего, если компилятор не встраивает что-то достаточно маленькое, чтобы вы могли ожидать полезного улучшения производительности, если оно было встроено, то компилятор знает о какой-то проблеме реализации, вы не такна самом деле будет хуже.В тех «серых» случаях, когда компилятор может пойти по любому пути, и вы просто превышаете некоторый порог, разница в производительности вряд ли будет значительной в любом случае.

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

3 голосов
/ 24 мая 2011

Или я могу спросить, почему встроенное ключевое слово является просто подсказкой?

Потому что вы "могли бы" знать лучше, чем компилятор.

В большинстве случаев,для функций, не помеченных как встроенные (и правильно объявленные / определенные), компилятор, в зависимости от его конфигурации и реализации, сам оценит, может ли функция быть встроенной или нет.

Например, большинство компиляторов автоматически вставляют функции-члены, которые полностью определены в заголовке, если код не является длинным и / или слишком сложным.Это потому, что, поскольку функция доступна в заголовке, почему бы не вставить ее как можно больше?Однако этого не происходит, например, в режиме отладки для Visual Studio: в отладке отладочная информация по-прежнему должна отображать двоичный код функций, поэтому она избегает встраивания, но все же встроенные функции будут помечены как встроенные, поскольку пользователь требуетЭто.Это полезно, если вы хотите пометить функции, которые вам не нужны, чтобы иметь информацию о времени отладки (например, простые методы получения), в то же время получая более высокую производительность во время отладки.В режиме Release (по умолчанию) компилятор агрессивно вставляет все, что может, затрудняя отладку некоторой части кода, даже если вы активируете отладочную информацию.

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

Поскольку встраивание зависит как от контекста вызывающего, так и вызываемого, нет«правило».Часто советуют просто игнорировать явную пометку функции как встроенную, но в двух случаях:

  1. , если вам нужно поместить определение функции в заголовок, он просто должен быть встроенным;часто это касается шаблонных (членских или нет) функций и других служебных функций, которые являются просто ярлыками;
  2. , если вы хотите, чтобы определенный компилятор вел себя определенным образом во время компиляции, например, пометив некоторые функции-члены как встроенныевстроенный даже в конфигурации отладки на компиляторах Visual Studio, например.

Всегда ли компилятор делает это лучше, чем программист?

Нет, поэтому иногдаможет помочь использование встроенного ключевого слова.Программист может иногда иметь лучшее общее представление о том, что необходимо, чем компилятор.Например, если программист хочет, чтобы его двоичный файл был наименьшим, в зависимости от кода, встраивание может быть вредным.В быстродействии требуется применение, агрессивное наложение может очень помочь.Как бы компилятор узнал, что требуется?Он должен быть настроен и иметь возможность точно знать, что на самом деле хочет быть встроенным.

0 голосов
/ 24 мая 2011

Ошибочное предположение.

Там есть способ.Это пишется #define.И для многих ранних проектов C это было достаточно.inline было достаточно другим - намек, лучшая семантика - что его можно было добавить помимо макросов.Но после того, как у вас было и то, и другое, между третьим вариантом оставалось мало места, один с более хорошей семантикой, но не обязательный.

0 голосов
/ 24 мая 2011

Если вам действительно нужно принудительно встроить функцию (почему?), Вы можете сделать это: скопировать код и вставить его или использовать макрос.

...