7.3 Нечёткая связь
В C++ есть несколько конструкций, которые требуют места в объектном файле, но не чётко связаны с одним блоком трансляции. Мы говорим, что у этих конструкций «нечёткая связь». Обычно такие конструкции генерируются там, где они нужны, хотя иногда можно поступить более хитро.
- Встроенные функции
-
Встроенные функции обычно определяются в файле заголовков, который может включаться во многие разные трансляции. В идеале они могут быть обычно встроены, но иногда необходима внедренная копия, если адрес функции взяты или если встраивание не удалось. В общем случае мы генерируем внедренную копию во всех блоках трансляции, где она необходима. В качестве исключения, мы генерируем только встроенные виртуальные функции с vtable, так как это всегда требует копии.
Локальные статические переменные и строковые константы, используемые во встроенной функции, также считаются имеющими нечёткую связь, поскольку они должны быть объединены между всеми встроенными и внедрёнными экземплярами функции.
- VTable
-
Виртуальные функции C++ в большинстве компиляторов реализуются с помощью таблицы поиска, известной как vtable. Vtable содержит указатели на виртуальные функции, предоставляемые классом, и каждый объект класса содержит указатель на свою vtable (или vtables в некоторых ситуациях множественного наследования). Если класс объявляет какие-либо не встроенные, не чистые виртуальные функции, то первая из них выбирается в качестве «ключевого метода» для класса, а vtable генерируется только в блоке трансляции, где определён ключевой метод.
Примечание: Если выбранный ключевой метод впоследствии определяется как встроенный, vtable всё равно генерируется в каждом блоке трансляции, который его определяет. Убедитесь, что любые встроенные виртуальные функции объявлены встроенными в теле класса, даже если они не определены там.
-
type_infoобъекты -
C++ требует информации о типах, чтобы реализовать ‘dynamic_cast’, ‘typeid’ и обработку исключений. Для полиморфных классов (классов с виртуальными функциями) объект ‘type_info’ записывается вместе с vtable, чтобы ‘dynamic_cast’ мог определить динамический тип объекта класса во время выполнения. Для всех остальных типов мы записываем объект ‘type_info’, когда он используется: при применении ‘typeid’ к выражению, при выбрасывании объекта или при ссылке на тип в блоке catch или спецификации исключения.
- Инкапсуляции шаблонов
-
Почти всё в этом разделе также относится к инкапсуляциям шаблонов, но есть и другие варианты. См. Где шаблон?.
При использовании с GNU ld версии 2.8 или новее на ELF-системе, такой как GNU/Linux или Solaris 2, или на Microsoft Windows, дублированные копии этих конструкций будут удалены на этапе компоновки. Это известно как поддержка COMDAT.
На целевых платформах, которые не поддерживают COMDAT, но поддерживают слабые символы, GCC использует их. Таким образом, одна копия перекрывает все остальные, но неиспользуемые копии всё ещё занимают место в исполняемом файле.
Для целевых платформ, которые не поддерживают ни COMDAT, ни слабые символы, большинство сущностей с нечёткой связью генерируются как локальные символы, чтобы избежать ошибок дублирования определений от компоновщика. Однако это не происходит для локальных статических переменных во встроенных функциях, поскольку наличие нескольких копий почти наверняка нарушит работу.
См. Объявления и определения в одном заголовке, для другого способа управления размещением этих конструкций.
Далее: Интерфейс C++, Предыдущее: Ограниченные указатели, Вверх: Расширения C++ [Содержание][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-8.5.0/gcc/Vague-Linkage.html