resueltos - Error de segmentación de C++ cuando se usa cout en la inicialización de variables estáticas
punteros c++ pdf (3)
Tengo un programa donde utilizo cout para emitir información de depuración. El código se ejecuta en la inicialización de una variable global estática, es decir, bastante temprano en la ejecución del programa. Cuando uso mi propio script de compilación para compilar el programa, segfaults en el primer uso de cout (solo un literal de cadena se desplaza a cout, por lo que no puede ser el valor). Utilicé valgrind para verificar escrituras anteriores en ubicaciones no válidas, pero no hay ninguna (y tampoco hay código que pueda generar esas escrituras, no hago demasiado antes de la salida). Cuando copio el código fuente en un proyecto de eclipse y dejo que el constructor incorporado de eclipse lo construya, todo funciona bien. No utilicé configuraciones de constructores raras compiladas con -ggdb -std=c++0x
, estas son las dos únicas banderas.
Entonces, ¿cuál puede ser el motivo por el que una entrada con un literal de cadena falla, si no hubo escrituras no válidas antes? ¿Cómo puede la configuración de construcción afectar esto?
(Lamento no poder darte un ejemplo mínimo, ya que este ejemplo simplemente compilaría bien en tu máquina, como lo hace para mí al usar el generador de eclipse)
Editar: Aquí está la stacktrace:
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
El último cuadro es mi código. La línea 92 simplemente dice:
std::cout << "Test";
Como ha señalado Luchian, no puede usar std::cout
antes de que se haya construido la primera instancia de ios_base::Init
. No es necesario definir una instancia, sin embargo; incluyendo <iostream>
debería ser suficiente.
El orden de inicialización se define dentro de una sola unidad de traducción. Si incluye <iostream>
en la parte superior de todos los archivos que tienen instancias estáticas, debería estar bien. Sin embargo, si el constructor de un objeto estático llama a una función en otra unidad de traducción y la salida está en esa unidad de traducción, no es suficiente incluir <iostream>
solo en la unidad de traducción que realiza la salida. Debe incluirlo en la unidad de traducción donde se definen las variables estáticas. Incluso si no hacen ningún resultado.
La inicialización de variables estáticas es una tierra de nadie. Evitará problemas si evita hacer un trabajo importante allí. Tal vez debería envolver la variable estática en un patrón de Singleton para poder retrasar la inicialización la primera vez que se usa.
std::cout
es un objeto en almacenamiento estático. Se garantiza que se inicializará antes de ingresar al main
, pero no necesariamente antes de otras estáticas en su código. Parece que el fiasco de orden de inicialización estática.
Después de algunas excavaciones:
27.4.2.1.6 Clase ios_base :: Init
Init ();
3) Efectos: construye un objeto de clase Init. Si init_cnt es cero, la función almacena el valor uno en init_- cnt, luego construye e inicializa los objetos cin, cout, cerr, clog (27.3.1), wcin, wcout, wcerr y wclog (27.3.2). En cualquier caso, la función agrega uno al valor almacenado en init_cnt.