С++ Сегментация Ошибка при использовании 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";
Ответы
Ответ 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, чтобы вы могли отложить инициализацию в первый раз, когда она была использована.