简体   繁体   English

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

[英]C++ Segmentation Fault when using cout in static variable initialization

I have a program where I use cout to emit debug information. 我有一个程序,我使用cout发出调试信息。 The code is executed in the initialization of a static global variable, ie quite early in the program execution. 代码在静态全局变量的初始化中执行,即在程序执行的早期。 When I use my own build script to build the program, it segfaults at the first use of cout (only a string literal is shifted into cout, so it cannot be the value). 当我使用自己的构建脚本来构建程序时,它首次使用cout时会出现段错误(只有字符串文字被转移到cout中,所以它不能是值)。 I used valgrind to check for earlier writes to invalid locations, but there are none (and there is also no code that would be likely to generate those writes, I dont do too much before the output). 我使用valgrind检查早期写入无效位置,但没有(并且也没有可能生成这些写入的代码,我在输出之前不做太多)。 When I copy the source code to an eclipse project and let the eclipse built-in builder build it, then everything works fine. 当我将源代码复制到eclipse项目并让eclipse内置构建器构建它时,一切正常。 I used no weird builder settings simply compiled with -ggdb -std=c++0x , these are the only two flags. 我没有使用简单的编译器设置,只使用-ggdb -std=c++0x编译,这些是唯一的两个标志。

So what can be the reason that a cout with a string literal segfaults, if there were no invalid writes before? 那么,如果之前没有无效的写入,那么带有字符串文字段错误的cout可能是什么原因? How can the build configuration affect this? 构建配置如何影响这个?

(I am sorry I can give you no minimal example, as this example would simply compile fine at your machine, as it does for me when using the eclipse builder) (对不起,我不能给你一个最小的例子,因为这个例子可以简单地在你的机器上编译,就像在使用eclipse构建器时那样)

Edit: Here is the 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

The last frame is my code. 最后一帧是我的代码。 Line 92 simply reads: 第92行简单地写道:

std::cout << "Test";

std::cout is an object in static storage. std::cout是静态存储中的对象。 It's guaranteed to be initialized before entering main , but not necessarily before other statics in your code. 它保证在进入main之前初始化,但不一定在代码中的其他静态之前初始化。 Seems like the static initialization order fiasco. 看起来像静态初始化命令fiasco。

After some digging: 经过一番挖掘:

27.4.2.1.6 Class ios_base::Init 27.4.2.1.6类ios_base :: Init

Init ();

3) Effects: Constructs an object of class Init. 3)效果:构造类Init的对象。 If init_cnt is zero, the function stores the value one in init_- cnt , then constructs and initializes the objects cin, cout, cerr, clog (27.3.1), wcin, wcout, wcerr, and wclog (27.3.2). 如果init_cnt为零,则函数将值1存储在init_-cnt中,然后构造并初始化对象cin,cout,cerr,clog(27.3.1),wcin,wcout,wcerr和wclog(27.3.2)。 In any case, the function then adds one to the value stored in init_cnt . 在任何情况下,函数然后将一个值添加到存储在init_cnt中的值。

As Luchian has pointed out, you cannot use std::cout before the first instance of ios_base::Init has been constructed. 正如Luchian指出的那样,在构造ios_base::Init的第一个实例之前,不能使用std::cout You don't have to define an instance, however; 但是,您不必定义实例; including <iostream> should be enough. 包括<iostream>应该足够了。

Order of initialization is defined within a single translation unit. 初始化的顺序一个翻译单元中定义的。 If you include <iostream> at the top of all files which have static instances, you should be OK. 如果在所有具有静态实例的文件的顶部包含<iostream> ,则应该没问题。 If the constructor of a static object calls a function in another translation unit, however, and the output is in that translation unit, it is not sufficient to include <iostream> only in the translation unit which does the output. 但是,如果静态对象的构造函数调用另一个转换单元中的函数,并且输出位于该转换单元中,则仅在执行输出的转换单元中包含<iostream>是不够的。 You must include it in the translation unit where the static variable(s) are defined. 您必须将其包含在定义静态变量的转换单元中。 Even if they don't do any output. 即使他们没有做任何输出。

Static variable initialization is a no-man's-land. 静态变量初始化是一个无人区。 You will avoid problems if you avoid doing significant work there. 如果你避免在那里做大量工作,你将避免问题。 Maybe you should wrap the static variable in a Singleton pattern so you can defer initialization to the first time it's used. 也许你应该将静态变量包装成Singleton模式,这样你就可以在第一次使用时将初始化推迟。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM