Подтвердить что ты не робот

С++ Сегментация Ошибка при использовании cout в инициализации статической переменной

У меня есть программа, в которой я использую cout для извлечения информации об отладке. Код выполняется при инициализации статической глобальной переменной, то есть в самом начале выполнения программы. Когда я использую собственную сборку script для сборки программы, она segfaults при первом использовании cout (только строковый литерал смещается в cout, поэтому он не может быть значением). Я использовал valgrind для проверки более ранних записей в недопустимых местах, но их нет (и нет также кода, который, вероятно, сгенерировал бы эти записи, я не делаю слишком много до выхода). Когда я копирую исходный код в проект eclipse и позволяю встроенному построителю eclipse строить его, тогда все работает нормально. Я не использовал никаких странных настроек компоновщика, просто скомпилированных с помощью -ggdb -std=c++0x, это только два флага.

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

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

Изменить: Вот стек:

0x00007ffff7b6d7d1 in std::ostream::sentry::sentry(std::ostream&) () from /usr/lib   /x86_64-linux-gnu/libstdc++.so.6
(gdb) backtrace
#0  0x00007ffff7b6d7d1 in std::ostream::sentry::sentry(std::ostream&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1  0x00007ffff7b6dee9 in std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#2  0x00007ffff7b6e2ef in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) ()
  from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00000000004021be inTest::fill (this=0x6120f8, funcs=...) at inTest.cpp:92

Последний кадр - мой код. Строка 92 просто читает:

std::cout << "Test";
4b9b3361

Ответ 1

Как отметил Лучиан, вы не можете использовать std::cout до первого экземпляр ios_base::Init. Вам не нужно однако определить экземпляр; в том числе <iostream> должно быть достаточно.

Порядок инициализации определен в пределах одной единицы перевода. Если вы включили <iostream> в начало всех файлов, которые имеют статический экземпляров, вы должны быть в порядке. Если конструктор статического объекта однако вызывает функцию в другой блок перевода, а выход - в этой единицы перевода недостаточно включить <iostream> только в единицах перевода, которая выводит результат. Вы должны включить его в блоке перевода, где статическая переменная определены. Даже если они не производят никакого вывода.

Ответ 2

std::cout - объект в статическом хранилище. Он должен быть инициализирован перед входом main, но не обязательно перед другой статикой вашего кода. Похоже на фиаско порядка статического инициализации.

После некоторого рытья:

27.4.2.1.6 Класс ios_base:: Init

Init ();

3) Эффекты: Создает объект класса Init. Если init_cnt ноль, функция сохраняет значение one в init_- cnt, затем строит и инициализирует объекты cin, cout, cerr, clog (27.3.1), wcin, wcout, wcerr и wclog (27.3.2). В любом случае функция тогда добавляет один к значению, хранящемуся в init_cnt.

Ответ 3

Статическая инициализация переменных - это не-человек. Вы избежите проблем, если не будете делать там значительную работу. Возможно, вы должны обернуть статическую переменную в Singleton pattern, чтобы вы могли отложить инициализацию в первый раз, когда она была использована.