C ++ статическая глобальная не POD: теория и практика - PullRequest
9 голосов
/ 08 октября 2009

Я читал документы по соглашениям о кодировании Qt и наткнулся на следующий абзац:

Все, что имеет конструктор или нуждается в запуске кода для инициализации, не может использоваться как глобальный объект в коде библиотеки, так как оно не определено, когда этот конструктор / код будет запущен (при первом использовании, при загрузке библиотеки, до main ( ) или вовсе ). Даже если время выполнения инициализатора определено для разделяемых библиотек, у вас возникнут проблемы при перемещении этого кода в плагине или при статической компиляции библиотеки.

Я знаю, что говорит теория , но я не понимаю, что такое "не совсем". Иногда я использую не-POD глобальную констатную статику (например, QString), и мне никогда не приходило в голову, что они не могут быть инициализированы ... Это специфично для общих объектов / DLL? Это происходит только для сломанных компиляторов?

Что вы думаете об этом правиле?

Ответы [ 5 ]

10 голосов
/ 08 октября 2009

В части «совсем нет» просто говорится, что в стандарте C ++ об этой проблеме ничего не сказано. Он не знает об общих библиотеках и, следовательно, ничего не говорит о взаимодействии определенных функций C ++ с ними.

На практике я видел глобальные статические глобальные переменные без POD, используемые в Windows, OSX и многих версиях Linux и других Unix, как в программах с графическим интерфейсом, так и в программах командной строки, как плагины и как автономные приложения. По крайней мере, у одного проекта (который использовал статические глобальные переменные не POD) были версии для полного набора всех этих комбинаций. Единственная проблема, которую я когда-либо видел, заключалась в том, что какая-то очень старая версия GCC генерировала код, который вызывал dtors таких объектов в динамических библиотеках, когда исполняемый файл останавливался, а не когда библиотека выгружалась. Конечно, это было фатально (код библиотеки был вызван, когда библиотеки уже не было), но это было почти десять лет назад.

Но, конечно, это еще ничего не гарантирует.

2 голосов
/ 08 октября 2009

C ++ не определяет порядок выполнения статических инициализаторов для объектов в разных единицах компиляции (порядок четко определен в единицах компиляции).

Рассмотрим ситуацию, когда у вас есть 2 статических объекта A и B, определенных в разных единицах компиляции. Скажем, объект B фактически использует объект A в своей инициализации.

В этом сценарии возможно, что B будет инициализирован первым и вызовет неинициализированный объект A. Это может быть одной вещью, которая подразумевается под «совсем нет» - объект используется, когда у него не было возможности инициализировать его самостоятельно (даже если он может быть инициализирован позже).

Я полагаю, что динамическое связывание может добавить сложности, о которых я не думал, потому что объект никогда не будет инициализирован. В любом случае, суть в том, что static initializatino создает достаточно потенциальных проблем, которых следует избегать, где это возможно, и очень осторожно обрабатывать там, где вы должны его использовать.

2 голосов
/ 08 октября 2009

Я не вижу проблем с наличием глобальных объектов с конструкторами.

Они просто не должны зависеть от других глобальных объектов в своем конструкторе (или деструкторе).

Но если у них есть зависимости, то зависимый объект должен либо находиться в одной и той же единице компиляции, либо быть лениво оцененным, чтобы вы могли принудительно оценить его перед использованием.

Код в конструкторе также не должен зависеть от того, когда (это связано с зависимостями, но не совсем так), когда он выполняется, но вы можете с уверенностью предположить, что он будет построен по крайней мере (непосредственно перед вызывается метод), а C ++ гарантирует порядок уничтожения в обратном порядке.

Не так сложно придерживаться этих правил.

2 голосов
/ 08 октября 2009

Если статический объект определен в объекте, на который нет ссылок, компоновщик может полностью удалить объект, включая код статического инициализатора. будет регулярно делать это для библиотек (вот почему libc не полностью связывается при использовании его частей в gnu, например)

Интересно, я не думаю, что это специфично для библиотек. Это может произойти для объектов даже в основной сборке.

2 голосов
/ 08 октября 2009

Я не думаю, что конструкторы статических объектов могут быть исключены. Вероятно, существует путаница с тем фактом, что статическая библиотека часто представляет собой просто набор объектов, которые являются токенами в исполняемом файле , если на они ссылаются. Некоторые статические объекты спроектированы так, чтобы на них не ссылались за пределами их содержащего объекта, и поэтому объектный файл помещается в исполняемый файл, только если от них есть другая зависимость. Это не так в некоторых шаблонах (например, при использовании статического объекта, который регистрирует себя).

...