C++ статический глобальный не-POD: теория и практика

Во-первых, нет никакого смысла в притворстве, что одиночные элементы так или иначе лучше или более приемлемы, чем globals. Одиночный элемент является просто глобальным, наряженным для сходства с ООП. С набором других добавленных проблем.

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

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

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

9
задан Community 23 May 2017 в 10:33
поделиться

5 ответов

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

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

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

10
ответ дан 4 December 2019 в 11:42
поделиться

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

2
ответ дан 4 December 2019 в 11:42
поделиться

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

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

2
ответ дан 4 December 2019 в 11:42
поделиться

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

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

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

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

2
ответ дан 4 December 2019 в 11:42
поделиться

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

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

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

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

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

2
ответ дан 4 December 2019 в 11:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: