在静态变量初始化中使用cout时的C ++分段错误

时间:2012-09-07 13:03:58

标签: c++ initialization segmentation-fault cout

我有一个程序,我使用cout发出调试信息。该代码在静态全局变量的初始化中执行,即在程序执行的早期。当我使用自己的构建脚本来构建程序时,它首次使用cout时会出现段错误(只有字符串文字被转移到cout中,所以它不能是值)。我使用valgrind检查早期写入无效位置,但没有(并且也没有可能生成这些写入的代码,我在输出之前不做太多)。当我将源代码复制到eclipse项目并让eclipse内置构建器构建它时,一切正常。我没有使用仅使用-ggdb -std=c++0x编译的奇怪的构建器设置,这些是仅有的两个标志。

那么,如果之前没有无效写入,那么带有字符串文字段错误的cout可能是什么原因?构建配置如何影响这个?

(很抱歉,我不能给你一个最小的例子,因为这个例子可以简单地在你的机器上编译,就像在使用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";

3 个答案:

答案 0 :(得分:13)

std::cout是静态存储中的对象。保证在输入main之前初始化,但不一定在代码中的其他静态之前。看起来像静态初始化命令fiasco。

经过一番挖掘:

27.4.2.1.6类ios_base :: Init

  

Init ();

     

3)效果:构造类Init的对象。如果init_cnt是   零,该函数将值1存储在init_-cnt中,然后   构造并初始化对象cin,cout,cerr,clog(27.3.1),   wcin,wcout,wcerr和wclog(27.3.2)。无论如何,那么功能   将一个值添加到存储在init_cnt中的值。

答案 1 :(得分:12)

正如Luchian指出的那样,你不能在第一个之前使用std::cout 已构建ios_base::Init的实例。你不必 然而,定义一个实例;包括<iostream>就足够了。

在单个翻译单元中定义初始化顺序 。 如果在所有具有静态的文件的顶部包含<iostream> 实例,你应该没问题。如果是静态对象的构造函数 但是,在另一个翻译单元中调用一个函数,输出是 在该翻译单元中,仅包含<iostream>是不够的 仅在执行输出的翻译单元中。你必须包括它 在定义静态变量的转换单元中。甚至 如果他们不做任何输出。

答案 2 :(得分:0)

静态变量初始化是一个无人区。如果你避免在那里做大量工作,你将避免问题。也许您应该将静态变量包装在Singleton pattern中,这样您就可以将初始化推迟到第一次使用时。