Как использование безымянных пространств имен в заголовках может привести к нарушениям ODR?

В Руководстве по стилю Google C ++ Пространства имен В разделе говорится, что «Использование безымянных пространств имен в заголовочных файлах может легко привести к нарушениям C ++ One Definition Rule (ODR).«

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

5

Решение

Причина в том, что если вы действительно используете что-либо в анонимном
пространство имен, вы рискуете неопределенным поведением. Например:

namespace {
double const pi = 3.14159;
}

inline double twoPiR( double r ) { return 2.0 * pi * r; }

Правило для встроенных функций (и классов, и шаблонов, и
все остальное, что должно быть определено в множественном переводе
единиц), что токены должны быть идентичны (как правило,
если вы не нажмете какой-то макрос), и что все символы должны связываться
одинаково. В этом случае каждая единица перевода имеет отдельный
экземпляр pi, Итак pi в twoPiR привязывается к другому
сущность в каждой единице перевода. (Есть несколько исключений,
но все они включают в себя интегральные выражения.)

Конечно, даже без анонимного пространства имен это было бы
неопределенное поведение здесь (так как const означает внутреннюю связь
по умолчанию), но основной принцип держится. Любое использование в заголовке
что-нибудь в безымянном пространстве имен (или любой объект const, определенный в
заголовок) может вызвать неопределенное поведение. Будь то
реальная проблема или нет, зависит, но, конечно, все, что
действительно включает в себя адрес piвыше, будет вызывать
проблемы. (Я говорю «действительно» здесь, потому что есть много случаев
где адрес или ссылка используются формально, но в
На практике, встроенное расширение приведет к значению на самом деле
использовался. И, конечно же, токен 3.14159 является 3.14159
независимо от того, где он появляется.)

5

Другие решения

В test.h

namespace {
int x;
}

namespace{
int x;
}

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

0

По вопросам рекламы [email protected]