Статическая переменная-член для класса, который загружается динамически

Если бы я должен был загрузить некоторые символы, используя что-то вроде dlopen в C ++, в то время как другие классы в этом модуле перевода имели static переменные-члены, каково поведение этих статических переменных-членов. Они инициализируются или нет, потому что библиотека на самом деле не загружается только символами, которые вы искали (что, я думаю, последнее неверно, потому что, если символ, который вы искали, нуждается в них, их тоже нужно загрузить)?

1

Решение

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

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

Слово «статика», к сожалению, перегружено в «Стандарте», поэтому я не знаю Стандарт ссылается на оба статическая продолжительность хранения а также статическая инициализация. Типы хранения, определенные Стандартом, являются статическими, потоковыми, автоматическими и динамическими. Они как они звучат. статический срок хранения означает, что время жизни такой переменной равно всей продолжительности программы.

статический инициализация это четкое понятие. Хотя переменная может быть сохранена только один раз за выполнение программы, значение, с которым она будет инициализироваться, может быть неизвестно при запуске программы. В начале программы все переменные со статической длительностью хранения будут инициализированы нулями, а те, которые могут быть, будут инициализированы константами. Тонкие моменты есть в §3.6.2, но примерно, статическая переменная будет инициализирована константой, если ее инициализация зависит только от константных выражений. Вместе нулевая инициализация и постоянная инициализация называются статическая инициализация. Аналог динамическая инициализация. Это интересные, но, к сожалению, не существует переносимого способа принудительной динамической инициализации main() сначала выполняется, в случае динамического связывания или до dlopen() возвращает, в случае динамической загрузки. C ++ просто не требует такого.

Ключевая часть Стандарта C ++ 11 содержится в §3.6.2:

Это определяется реализацией, является ли динамическая инициализация
нелокальная переменная со статической продолжительностью хранения выполняется до
Первое изложение основного. Если инициализация откладывается до некоторого
момент времени после первого изложения основного, это должно произойти до
первое использование odr (3.2) любой функции или переменной, определенной в
та же единица перевода, что и для инициализируемой переменной.

Тем не менее, если вы экспериментировали, вы заметили, что иногда это работает. Иногда вы можете получить произвольный код для запуска при загрузке библиотеки, вставив его в конструкторы статических переменных. Происходит ли это, зависит только от компилятора (а не от компоновщика). Manpage для dlopen объясняет.

Если динамическая библиотека экспортирует подпрограмму с именем _init (), то этот код выполняется после загрузки до возврата dlopen ().

Изучив вывод asm небольшого общего объекта, написанного на стандартном C ++, я вижу, что clang 3.4 и g ++ 4.8 оба добавляют раздел _init, однако они не обязаны это делать.

Что касается обходных путей, расширение gcc, которое стало обычным явлением, позволяет контролировать это поведение. Добавляя атрибут конструктора к функциям, мы можем настаивать на том, чтобы они запускались при инициализации библиотеки. Связанная man-страница для dlopen предлагает использовать этот метод.

Увидеть Документация GCC на атрибуты функции и этот ТАК вопрос который имеет пример использования. Это расширение поддерживается gcc, clang, IBM XL, и я предполагаю, что icc также поддерживает его. MSVC не поддерживает это, но я понимаю, что есть нечто подобное.

По-настоящему портативное решение неуловимо. Как сказано в Стандарте, если вы можете каким-либо образом вызвать использование odr в той же единице перевода, что и статическая переменная, тогда статическая переменная должна быть инициализирована. Вызов функции, даже фиктивной функции только для этой цели, будет работать.

2

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


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector