Может кто-нибудь объяснить мне этот пример из наиболее авторитетных ISO C ++ FAQ? Код выглядит так:
// Fred.h
class Fred {
public:
static const int maximum = 42;
// ...
};
// Fred.cpp
#include "Fred.h"const int Fred::maximum;
// ...
И утверждение, которое я не могу получить:
Если вы когда-нибудь возьмете адрес Fred :: Maximum, например, передадите его по ссылке или явно &Fred :: Maximum, компилятор позаботится о том, чтобы у него был уникальный адрес. Если нет, Fred :: Maximum не займет даже места в области статических данных вашего процесса.
Компилятор обрабатывает файлы .cpp отдельно и не знает, что делают другие файлы с данными, определенными в обрабатываемых в данный момент. Итак, как компилятор может решить, должен ли он выделять уникальный адрес или нет?
Оригинальный предмет здесь: https://isocpp.org/wiki/faq/ctors#static-const-with-initializers
Запись FAQ говорит, что const int Fred::maximum;
должен быть определен ровно в одной единице компиляции. Однако это верно только в том случае, если переменная УСО используемый программой (например, если к ней привязана ссылка).
Если переменная не УСО используемый тогда определение может быть опущено.
Однако, если переменная на самом деле УСО используемый но не имеет определения, то это неопределенное поведение без диагностической необходимости. Как правило, если адрес переменной требуется, но определение опущено, компоновщик хорошего качества пропустит ошибку «неопределенная ссылка».
Но вы не всегда хотите полагаться на определенные проявления неопределенного поведения. Поэтому рекомендуется всегда включать определение const int Fred::maximum;
,
Процитированный абзац в вашем вопросе предназначен для решения проблемы потенциального программиста: «Ну, я не могу сохранить 4 байта в своей области статических данных, опуская определение в некоторых случаях?»
Это говорит о том, что компилятор / компоновщик мог выполнить анализ всей программы и принять собственное решение по оптимизации, чтобы опустить определение, если оно определило, что определение не использовалось.
Хотя линия const int Fred::maximum;
определяется как выделение памяти для int
это разрешенная оптимизация, потому что соответствующая программа не может измерить, была ли память фактически выделена для int
который не УСО используемый.
Автор этой записи FAQ явно ожидает, что компилятор / компоновщик действительно сделает это.
Формулировка в Стандарте о УСО использование предназначен для поддержки следующей модели компиляции / компоновки:
Для этого не требуется, чтобы компилятор выдавал сообщение об ошибке «неопределенная ссылка», потому что это усложняло бы оптимизацию компиляторов. Может случиться, что на другом этапе оптимизации будет полностью удалена часть объектного файла, содержащая ссылку. Например, если оказалось УСО использование только когда-либо происходило в функции, которая никогда не вызывалась.
Компилятор ничего не решает. Для переводческих единиц, где static
член класса не определен, объектный модуль, созданный компилятором, содержит неразрешенную ссылку на символ.
Когда все объектные модули связаны друг с другом, компоновщик отвечает за завершение работы и разрешение всех неразрешенных ссылок от единиц перевода, ссылающихся на статический символ, на единичную единицу перевода, для которой определен символ.