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’ к выражению, при бросании объекта или при ссылке на тип в обработчике исключений или спецификации исключения.
- Шаблонные инстанциации
-
Практически всё в этом разделе также относится к шаблонным инстанциациям, но есть и другие варианты. См. Где шаблон?.
При использовании с GNU ld версии 2.8 или новее на системе ELF, такой как GNU/Linux или Solaris 2, или на Microsoft Windows, дублированные копии этих конструкций будут удалены на этапе компоновки. Это известно как поддержка COMDAT.
На целевых платформах, которые не поддерживают COMDAT, но поддерживают слабые символы, GCC использует их. Таким образом, одна копия перекрывает все остальные, но неиспользуемые копии по-прежнему занимают место в исполняемом файле.
Для целей, которые не поддерживают ни COMDAT, ни слабые символы, большинство сущностей с неявными связями генерируются как локальные символы, чтобы избежать ошибок дублирования определений от компоновщика. Однако это не происходит для локальных статических переменных в встроенных функциях, поскольку наличие нескольких копий почти наверняка нарушит работу.
См. Объявления и определения в одном заголовке для другого способа управления размещением этих конструкций.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-13.3.0/gcc/Vague-Linkage.html