Статическая инициализация C ++ против __attribute __ ((конструктор)) - PullRequest
17 голосов
/ 08 декабря 2011

Пример:

struct Foo { Foo() { printf("foo\n"); } };
static Foo foo;

__attribute__((constructor)) static void _bar() { printf("bar\n"); }

Определяется ли сначала детерминистическая погоду foo или bar?

(Я надеюсь и ожидаю, что конструкторы статических объектов всегда выполняются первымино не уверен, и документ GCC об атрибуте конструктора ничего об этом не говорит.)

Ответы [ 2 ]

14 голосов
/ 08 декабря 2011

foo будет напечатан первым, поскольку объекты инициализируются в порядке их объявлений.Запустите и посмотрите:

Кстати, __attribute__((constructor)) не является стандартом C ++.Это расширение GCC.Таким образом, поведение вашей программы зависит от того, как GCC определил ее.Короче говоря, он определяется реализацией, в соответствии с которым foo печатается первым.

doc говорит:

Атрибут constructor вызывает функциювызываться автоматически до того, как выполнение входит в main ().Точно так же атрибут деструктора вызывает автоматический вызов функции после завершения main () или вызова exit ().Функции с этими атрибутами полезны для инициализации данных, которые будут использоваться неявно во время выполнения программы.

Вы можете предоставить необязательный целочисленный приоритет для управления порядком, в котором выполняются функции конструктора и деструктора.Конструктор с меньшим номером приоритета запускается перед конструктором с большим номером приоритета;обратное соотношение справедливо для деструкторов.Итак, если у вас есть конструктор, который выделяет ресурс, и деструктор, который выделяет один и тот же ресурс, обе функции обычно имеют одинаковый приоритет. Приоритеты для функций конструктора и деструктора те же, что и для объектов C ++ области имен (см. Атрибуты C ++).

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

Полагаю, вы также хотели бы прочитать это:

Если вы хотите контролировать / изменять порядок инициализации, вы можете использовать атрибут init_priority,предоставление приоритета .Взято с страницы :

Some_Class  A  __attribute__ ((init_priority (2000)));
Some_Class  B  __attribute__ ((init_priority (543)));

Здесь B инициализируется до A.

1 голос
/ 09 декабря 2011

Кажется недетерминированным. У меня также был foo\nbar\n в качестве результата примера в моем вопросе при компиляции с GCC. Однако при компиляции с LLVM / Clang я получаю bar\nfoo\n.

Но, поскольку я не уверен, что это может быть ошибкой в ​​Clang, я заполнил отчет об ошибке здесь . Редактировать: Я получил там ответ, и похоже, что это действительно ошибка в Clang, которая еще не исправлена. Не уверен, что из этого сделать вывод. Ожидаемое и ожидаемое поведение действительно здесь детерминировано, однако вы не можете зависеть от него, так как есть хотя бы один главный компилятор (Clang), который делает это неправильно (или отличается от GCC, если мы примем это как спецификацию для __attribute__((constructor))).

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

...