Си++: различия между версиями

Содержимое удалено Содержимое добавлено
Строка 88:
Встроенные функции обладают всеми достоинствами функций, которых лишены макросы: они приводят к типу, они знают об области видимости, они могут содержать условные операторы, они могут быть (см. ниже) перегруженными, или функциями-членами, или членами пространств имён, или функциями-друзьями, или задаваться шаблонами, или быть параметрами шаблонов. Макросам всё это недоступно.
 
Даже более, Стандарт чётко требует от компиляторов, чтобы программисту не требовалось задумываться на тему "а что, если вдруг", т.к. семантика программы, независимо от того, встраивается ли какая-либо функция или нет, оставалась неизменной. Поэтому, например, если в <tt>inline</tt>-функции присутствуют локальные <tt>static</tt>-переменные с неконстантным выражением инициализации, то соблюсти единственность и своевременность этой инициализации независимо от того, какое именно встраивание этой функции будет выполнено первым после запуска программы - это задача компилятора. В прежней редакции Стандарта, называемой С++03, это правило могло не соблюдаться в случае многопоточных приложений, т.к. многопоточность в той редакции на уровне языка явно не поддерживалась. Однако в редакции C++11 эта проблема уже явно оговорена как долженствующая быть решена средствами компилятора и/или библиотек. Также вполне возможно взять указатель на встроенную функцию, и этот указатель будет её чётко и однозначно идентифицировать. (Есть некоторые оговорки касательно виртуальных методов классов, однако их вызовы далеко не всегда могут быть встроены.) И по этой же причине компилятор всегда обязан генерировать вызываемый аналог встраиваемой функции и помещать его в объектный код, даже если ему никогда этот вызываемый аналог не потребовался. Это связано с тем, что ввиду раздельной компиляции единиц трансляции компилятор не знает наверняка, будет ли ему доступно тело функции везде в программе, ибо если нет, тогда ему придётся сгенерировать не встраивание, а вызов, разрешить который будет являться задачей линкера. Исключений тут может быть всего одно: если <tt>inline</tt> функция является <tt>static</tt>, т.е. имеет внутреннее связывание. Только в этом случае компилятор может быть уверен, что ниоткуда извне такая функция вызвана быть не может. Но даже в этом случае мы можем "заставить" его сгенерировать вызываемый вариант, стоит только получить на неё указатель.
 
И в то же, несмотря ни на что, время тело встроенной функции, подобно макросу, пишется там же, где её заголовок; обычно это заголовочный файл. Так, например, <font color=red>неправильно, если sqr.h включается более чем в одном cpp-шнике</font>, а потому так писать <font color=red>очень нежелательно</font>: