У меня есть программа, в которой я использую cout для передачи отладочной информации. Код выполняется при инициализации статической глобальной переменной, т. Е. Довольно рано при выполнении программы. Когда я использую свой собственный скрипт сборки для сборки программы, он вызывает ошибки при первом использовании 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";
Как указал Лучиан, вы не можете использовать std::cout
до первого
экземпляр ios_base::Init
был построен. Вам не нужно
определить экземпляр, однако; в том числе <iostream>
должно быть достаточно.
Порядок инициализации является определяется в пределах одной единицы перевода.
Если вы включите <iostream>
вверху всех файлов, которые имеют статический
случаи, вы должны быть в порядке. Если конструктор статического объекта
однако вызывает функцию в другом модуле перевода, и вывод
в этой единице перевода недостаточно включить <iostream>
только в блоке перевода, который делает вывод. Вы должны включить это
в блоке перевода, где определены статические переменные. Четное
если они не делают никакого вывода.
std::cout
это объект в статическом хранилище. Он гарантированно будет инициализирован перед входом main
, но не обязательно перед другими статиками в вашем коде. Похоже, статический порядок инициализации фиаско.
После некоторого копания:
Init ();
3) Эффекты: Создает объект класса Init. Если init_cnt
ноль, функция сохраняет значение один в init_- cnt, затем
создает и инициализирует объекты cin, cout, cerr, clog (27.3.1),
wcin, wcout, wcerr и wclog (27.3.2). В любом случае функция тогда
добавляет единицу к значению, хранящемуся в init_cnt.
Инициализация статической переменной — ничейная земля. Вы избежите проблем, если не будете выполнять там значительную работу. Может быть, вы должны обернуть статическую переменную в Синглтон так что вы можете отложить инициализацию до первого использования.