Ответ вслух Senior Сборка и линковка обновлено

Правило одного определения

Вопрос

Что такое ODR, какие нарушения диагностируются, а какие нет, и как inline и шаблоны с ним уживаются?

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

ODR говорит: у каждой не-inline функции и переменной в программе ровно одно определение, а у классов, перечислений, inline-функций и шаблонов определение может быть в каждой единице трансляции, где они используются, но все эти определения обязаны быть одинаковыми по токенам и смыслу.

Что должно прозвучать в ответе

  • Ровно одно определение не-inline функции и переменной на программу

  • Классы, inline-функции, шаблоны: по определению на единицу трансляции, и все одинаковые

  • Multiple definition: диагностируемое нарушение

  • Разные определения одного inline или класса: UB без диагностики

  • Источники: разные макросы и флаги, копипаста имён классов в разных файлах

  • Средства: безымянные пространства имён, модули, -fsanitize или детекторы ODR в линковщике (gold, lld)

Что могут спросить следом

  • Как разные значения NDEBUG могут нарушить ODR?
  • Почему два класса Node в разных .cpp опасны?

Разбор

ODR говорит: у каждой не-inline функции и переменной в программе ровно одно определение, а у классов, перечислений, inline-функций и шаблонов определение может быть в каждой единице трансляции, где они используются, но все эти определения обязаны быть одинаковыми по токенам и смыслу. Нарушение первого вида линковщик диагностирует: multiple definition или undefined reference. Нарушение второго вида обычно не диагностируется и является UB. Классический пример: в двух .cpp объявлены разные классы Node с одинаковым именем в глобальном пространстве имён, у обоих inline-конструкторы, линковщик оставит один, и второй файл будет конструировать объект неверного размера. Другой пример: заголовок с inline-функцией, поведение которой зависит от макроса, а макрос в разных файлах разный, или разные флаги вроде _GLIBCXX_DEBUG, меняющие раскладку контейнеров. Защищаюсь так: внутренние классы и функции кладу в безымянное пространство имён, флаги сборки одинаковые для всей программы, а детекторы ODR есть в линковщиках gold и lld и в AddressSanitizer (detect_odr_violation).

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.