Допустим, у меня есть заголовочный файл Resources.h
где я определил эти 5 структур:
const IColor COLOR_BLACK(255, 0, 0, 0);
const IColor COLOR_GRAY(255, 127, 127, 127);
const IColor COLOR_WHITE(255, 255, 255, 255);
const IColor COLOR_RED(255, 255, 0, 0);
const IColor COLOR_GREEN(255, 0, 255, 0);
С помощью const
(static
по умолчанию в C++
, так internal linkage
) они «находятся» в объеме единицы перевода.
Теперь, допустим, я включаю эти файлы 10 раз в мое приложение (из 10 разных .cpp
).
Когда я компилирую, создается объектный файл, и (позже) компоновщик соберет все эти объектные файлы вместе в уникальный исполняемый код для машины.
Означает ли это, что когда я run
программа, она будет выделять в памяти 10 раз каждый состав выше? то есть структуры 10х5?
Таким образом, они являются отдельными для единицы перевода, даже если они связаны позже? Или компоновщик достаточно умен, чтобы объединить их с уникальным распределением в памяти?
Не уверен, что я получил эти шаги по центру. Я новичок в C ++.
Да. Но (1) несколько байтов ничто по сравнению с обычным размером даже самого маленького исполняемого файла, и (2) он, вероятно, все равно будет оптимизирован. Если вы хотите избежать даже этого, используйте constexpr
, что заставляет их компилировать только значения времени.
В других новостях распространенным соглашением в C ++ является использование всех идентификаторов в верхнем регистре только для макросов. Это потому, что все заглавные буквы — это бельмо на глазу, поэтому конвенция должна быть зарезервирована для вещей, которые, как правило, плохи. Когда вы используете все заглавные буквы для чего-либо еще, вы (1), кажется, кричите, многим программистам, и (2) рискуете непреднамеренную замену текста, и (3) рискует неправильно понять, что означают эти имена.
C ++ не является Java или Python.
Эти языки получили соглашение всех заглавных букв для констант из раннего C, который не имел const
так что они должны были выражать константы как макросы препроцессора. То есть, соглашение Java и Python на самом деле является соглашением в верхнем регистре для макросов C. Использование макросов для констант устарело в C ++, и, в отличие от этих языков, в C ++ есть препроцессор.
Также будьте осторожны: префикс I
для типа является общим соглашением для указания (аннотация) интерфейс, но по вашим заявлениям IColor
должен быть конкретным, инстанцируемым типом.
Помните: стандарт определяет только поведение абстрактной машины. Реальная реализация не обязана эмулировать абстрактную машину, а только ее наблюдаемое поведение.
Так для абстрактной машины Экземпляр каждой внутренней переменной связи будет выделен на единицу перевода. Но поскольку они являются постоянными, вполне вероятно, что вы используете только их значение, а не они обращаются — в стандартные условия они, вероятно, не будут использоваться odr (одно правило определения). В этом случае они будут обработаны компилятором, как если бы они были просто константами времени компиляции, и для них не было бы выделено никакой памяти: они будут заменены компилятором на их значение.
Единственный случай, когда вы должны рассмотреть ручную оптимизацию, это IMHO, когда значение const дорого по размеру или времени изготовления. Тогда имеет смысл объявить их extern в заголовке и определить их только в одной единице перевода.
Если это не так, поскольку они имеют внутреннюю связь, это не является нарушением для одного правила определения, которое произошло бы, если бы они были определены с помощью внешней связи в разных единицах перевода.
TL / DR: во всех нормальных случаях, просто используйте идиому и продолжайте. И если вы действительно очень нехватка памяти, просто управляйте сгенерированным кодом сборки: вполне вероятно, что эти переменные будут оптимизированы и заменены их значением.
У вас может быть 10 из них на этапе компиляции, но в конечном итоге они могут быть оптимизированы на этапе компоновки.
Тем не менее, вы можете попробовать другой подход для таких определений константных переменных, если вам нужно быть уверенным из-за некоторых ограничений памяти.
Имея ваш заголовочный файл, поместите туда только объявления переменных как extern
,
// my_consts.h
extern const IColor COLOR_BLACK;
Затем создайте исходный файл, в котором отображаются фактические определения.
// my_consts.cpp
const IColor COLOR_BLACK(255, 0, 0, 0);
Таким образом, фактические определения компилируются один раз, и вы все равно можете ссылаться на них, поскольку они объявлены в заголовочном файле.
Кроме того, имея такие константы, было бы неплохо вставить их в некоторое пространство имен, чтобы избежать загрязнения глобального пространства имен, особенно если вы можете разделить их на несколько логических категорий.