На собрании стандартов ISO C ++ в Оулу в 2016 году комитет по стандартам проголосовал за предложение под названием « Встроенные переменные» в C ++ 17.
Говоря простым языком, что такое встроенные переменные, как они работают и для чего они полезны? Как следует объявлять, определять и использовать встроенные переменные?
const
.inline
ключевое слово выполняет для функций.inline
Ключевое слово, применительно к функциям, есть еще один важный эффект, который транслирует непосредственно к переменным.inline
Функция , которая предположительно объявлена в заголовочном файле, не приведет «дубликат символ» ошибка во время компоновки, даже если заголовок получает#include
d нескольких единиц перевода.inline
Ключевое слово, применительно к переменным, будет иметь точно такой же результат. Конец.inline
- это лишь слабый, необязательный запрос к оптимизатору. Компиляторы могут не встраивать запрошенные функции и / или встраивать те, которые вы не аннотировали. Скорее, фактическая цельinline
ключевого слова состоит в том, чтобы обойти множественные ошибки определения.Ответы:
Первое предложение предложения:
Гарантированный эффект
inline
применительно к функции состоит в том, что функция может быть определена идентично, с внешней связью, в нескольких единицах трансляции. На практике это означает определение функции в заголовке, который может быть включен в несколько единиц перевода. Предложение расширяет эту возможность до переменных.Итак, с практической точки зрения (теперь принятое) предложение позволяет вам использовать
inline
ключевое слово для определенияconst
переменной области пространства имен внешней связи или любогоstatic
члена данных класса в файле заголовка, так что множественные определения, которые возникают, когда этот заголовок включается в Компоновщик может использовать несколько единиц перевода - он просто выбирает одну из них.Вплоть до C ++ 14 включительно был внутренний механизм для этого, чтобы поддерживать
static
переменные в шаблонах классов, но не было удобного способа использовать этот механизм. Пришлось прибегнуть к хитростям вродеНачиная с C ++ 17 и далее, я считаю, что можно написать просто
… В заголовочном файле.
Предложение содержит формулировку
… Что позволяет упростить вышеизложенное до
… Как отметил TC в комментарии к этому ответу.
Кроме того,
constexpr
спецификатор подразумеваетinline
статические элементы данных, а также функции.Примечания:
¹ Для функции
inline
также есть намек на оптимизацию, что компилятор должен предпочесть заменять вызовы этой функции прямой заменой машинного кода функции. Этот намек можно игнорировать.источник
Kath::hi
), не обязательно должны быть константными.const
ограничение полностью снято.static std::string const hi = "Zzzzz...";
?Встроенные переменные очень похожи на встроенные функции. Он сообщает компоновщику, что должен существовать только один экземпляр переменной, даже если переменная присутствует в нескольких единицах компиляции. Компоновщику необходимо убедиться, что больше не создается копий.
Встроенные переменные могут использоваться для определения глобальных переменных в библиотеках только заголовков. До C ++ 17 им приходилось использовать обходные пути (встроенные функции или взлом шаблонов).
Например, одним из способов решения проблемы является использование синглтона Мейера со встроенной функцией:
У этого подхода есть некоторые недостатки, в основном с точки зрения производительности. Этих накладных расходов можно избежать с помощью шаблонных решений, но легко ошибиться.
С помощью встроенных переменных вы можете напрямую объявить его (без получения ошибки компоновщика нескольких определений):
Помимо библиотек только для заголовков, есть и другие случаи, когда могут помочь встроенные переменные. Нир Фридман освещает эту тему в своем выступлении на CppCon: Что разработчики C ++ должны знать о глобальных объектах (и компоновщике) . Часть о встроенных переменных и обходных путях начинается с 18 минут 9 секунд .
Короче говоря, если вам нужно объявить глобальные переменные, которые являются общими для модулей компиляции, объявление их как встроенных переменных в файле заголовка просто и позволяет избежать проблем с обходными путями до C ++ 17.
(Есть еще варианты использования синглтона Мейера, например, если вы явно хотите иметь ленивую инициализацию.)
источник
Минимальный запускаемый пример
Эта замечательная функция C ++ 17 позволяет нам:
constexpr
: Как объявить constexpr extern?main.cpp
notmain.hpp
notmain.cpp
Скомпилируйте и запустите:
GitHub вверх по течению .
См. Также: Как работают встроенные переменные?
Стандарт C ++ для встроенных переменных
Стандарт C ++ гарантирует, что адреса будут такими же. Стандартный черновик 10.1.6 C ++ 17 N4659 «Встроенный спецификатор»:
cppreference https://en.cppreference.com/w/cpp/language/inline объясняет, что если
static
не указан, то он имеет внешнюю связь.Реализация встроенной переменной GCC
Мы можем наблюдать, как это реализовано с помощью:
который содержит:
и
man nm
говорит оu
:Итак, мы видим, что для этого есть специальное расширение ELF.
До C ++ 17:
extern const
До C ++ 17 и в C мы могли добиться очень похожего эффекта с помощью
extern const
, что привело бы к использованию одной области памяти.Минусы
inline
:constexpr
с помощью этого метода, толькоinline
позволяет следующее: Как объявить constexpr extern?main.cpp
notmain.cpp
notmain.hpp
GitHub вверх по течению .
Альтернативы только для заголовков до C ++ 17
Это не так хорошо, как
extern
решение, но они работают и занимают только одну ячейку памяти:constexpr
Функция, потому чтоconstexpr
подразумеваетinline
иinline
позволяет (сил) определение появляться на каждом ЕП :и я уверен, что любой достойный компилятор встроит вызов.
Вы также можете использовать целочисленную переменную
const
илиconstexpr
статическую, как в:но вы не можете делать такие вещи, как получение его адреса, иначе он станет использоваться odr, см. также: https://en.cppreference.com/w/cpp/language/static «Постоянные статические члены» и Определение статических данных constexpr члены
С
В C ситуация такая же, как и в C ++ до C ++ 17, я загрузил пример по адресу: Что означает «статический» в C?
Единственное отличие состоит в том, что в C ++
const
подразумеваетсяstatic
для глобальных объектов, но не в C: семантика C ++ static const и const.Есть ли способ полностью встроить его?
TODO: есть ли способ полностью встроить переменную без использования памяти?
Очень похоже на то, что делает препроцессор.
Это потребует как-то:
Связанный:
Протестировано в Ubuntu 18.10, GCC 8.2.0.
источник
inline
почти не имеет отношения к встраиванию ни для функций, ни для переменных, несмотря на само слово.inline
не говорит компилятору что-либо встроить. Он говорит компоновщику убедиться, что существует только одно определение, что традиционно было работой программиста. Итак, "Есть ли способ полностью встроить его?" это как минимум вопрос совершенно не связанный.