同一段c++代码在g++ 4.6编译器中可以工作,但在5.1编译器中会崩溃

same piece of C++ code works in g++ 4.6 compiler but crashes with 5.1

本文关键字:编译器 工作 但在 崩溃 一段 c++ g++ 代码      更新时间:2023-10-16

下面的代码在g++ 4.6编译器下工作,但在g++ 5.1编译器下编译时由于分段错误而崩溃。变量访问gString导致分段错误。

#define _GLIBCXX_DEBUG 1
#define _GLIBCXX_USE_CXX11_ABI 0
#include<string>
#include<iostream>
#include<vector>
static std::string gString("hello");
static void
__attribute__((constructor))
initialize()
{
    gString.assign("hello world");
    return;
}
static void 
__attribute__((destructor)) 
finalize()
{
    return;
}
int main(int ac, char **av)
{
    //std::cerr<<gString;
    return 0;
}

GDB输出:

   Reading symbols from /home/rk/str...done.
(gdb) b initialize
Breakpoint 1 at 0x401419: file str.cc, line 15.
(gdb) r 
Starting program: /home/rk/str 
Breakpoint 1, initialize() () at str.cc:15
15      gString.assign("hello world");
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x00000000004018d6 in std::string::size() const () at /usr/include/c++/5/bits/basic_string.h:3118
3118          { return _M_rep()->_M_length; }
(gdb) bt
#0  0x00000000004018d6 in std::string::size() const () at /usr/include/c++/5/bits/basic_string.h:3118
#1  0x00000000004016ff in std::string::assign(char const*, unsigned long) () at /usr/include/c++/5/bits/basic_string.tcc:706
#2  0x000000000040166e in std::string::assign(char const*) () at /usr/include/c++/5/bits/basic_string.h:3542
#3  0x0000000000401428 in initialize() () at str.cc:15
#4  0x00000000004023dd in __libc_csu_init ()
#5  0x00007ffff71ad700 in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6
#6  0x0000000000401289 in _start ()

为什么在c++中使用__attribute__((constructor)),而不是简单地使用带有构造函数的全局对象?这些属性在C代码中很有用,但在c++中是多余的。

问题是你的构造函数在标准iostreams初始化之前运行,如果你在构造函数中使用全局对象,这不会是一个问题。

你可以试着给你的构造函数增加一个优先级,但我不认为它在这种情况下会有帮助:

__attribute__((constructor(999))) 

在gcc 4.9.2中也会出现运行时错误(参见ideone示例)。

问题与iostreams尚未初始化有关。注释掉cerr行,一切正常

显然,这是一个已知的问题。

编辑:附加备注

这个小的解决方法似乎是有效的,至少在4.9:使用c stdio而不是iostreams:

fprintf(stderr, "_initialize");  // this works

但是我完全同意Jonathan的建议,使用全局(单例?)对象完全依赖于定义良好的标准c++行为,除非你真的需要构造函数恰好在动态库加载的那一刻运行。