<分区>
有人可以帮助理解以下 seg fautl,以及为什么它在更改链接顺序时起作用:
common.h 文件:
#include <set>
struct T {
explicit T(const char*) {
Instances.insert(this);
}
static std::set<T*> Instances;
};
d.cc 文件:
#include "common.h"
T d(__FILE__);
main.cc 文件:
#include "common.h"
#include <set>
#include <iostream>
/*static*/ std::set<T*> T::Instances;
int main() {
std::cout << "T::Instances.size() = " << T::Instances.size() << std::endl;
while(true);
}
使用以下命令构建和运行:
g++ -c -g -Wall -Wextra d.cc -o d.o
g++ -c -g -Wall -Wextra main.cc -o main.o
g++ -g d.o main.o -o app
./应用
运行命令时出现段错误,回溯如下:
$ ./app
Segmentation fault (core dumped)
$ gdb ./app
(gdb) run
Starting program: /home/meodou/zdev/poc_at_7405/testi/app
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7afebca in std::local_Rb_tree_decrement (__x=0x6031e8 <T::Instances+8>) at ../../../../../libstdc++-v3/src/c++98/tree.cc:98
98 && __x->_M_parent->_M_parent == __x)
(gdb) bt
#0 0x00007ffff7afebca in std::local_Rb_tree_decrement (__x=0x6031e8 <T::Instances+8>) at ../../../../../libstdc++-v3/src/c++98/tree.cc:98
#1 0x0000000000401365 in std::_Rb_tree_iterator<T*>::operator-- (this=0x7fffffffdc50) at /usr/include/c++/5.3.1/bits/stl_tree.h:220
#2 0x000000000040102f in std::_Rb_tree<T*, T*, std::_Identity<T*>, std::less<T*>, std::allocator<T*> >::_M_get_insert_unique_pos (
this=0x6031e0 <T::Instances>, __k=@0x7fffffffde08: 0x6031d1 <d>) at /usr/include/c++/5.3.1/bits/stl_tree.h:1819
#3 0x0000000000400dfe in std::_Rb_tree<T*, T*, std::_Identity<T*>, std::less<T*>, std::allocator<T*> >::_M_insert_unique (this=0x6031e0 <T::Instances>,
__v=@0x7fffffffde08: 0x6031d1 <d>) at /usr/include/c++/5.3.1/bits/stl_tree.h:1863
#4 0x0000000000400d79 in std::set<T*, std::less<T*>, std::allocator<T*> >::insert (this=0x6031e0 <T::Instances>, __x=@0x7fffffffde08: 0x6031d1 <d>)
at /usr/include/c++/5.3.1/bits/stl_set.h:485
#5 0x0000000000400d47 in T::T (this=0x6031d1 <d>) at common.hh:6
#6 0x0000000000400ce0 in __static_initialization_and_destruction_0 (__initialize_p=1, __priority=65535) at d.cc:2
#7 0x0000000000400d0a in _GLOBAL__sub_I_d () at d.cc:2
#8 0x0000000000401b2d in __libc_csu_init ()
#9 0x00007ffff71a050f in __libc_start_main (main=0x40173b <main()>, argc=1, argv=0x7fffffffdf68, init=0x401ae0 <__libc_csu_init>, fini=<optimized out>,
rtld_fini=<optimized out>, stack_end=0x7fffffffdf58) at libc-start.c:245
#10 0x0000000000400bc9 in _start ()
所以这是我想要理解的东西。 第二件事是,如果我颠倒链接顺序:
From g++ -g d.o main.o -o app
To g++ -g main.o d.o -o app
程序运行没有段错误。
$ g++ -c -g -Wall -Wextra d.cc -o d.o
$ g++ -c -g -Wall -Wextra main.cc -o main.o
$ g++ -g main.o d.o -o app
$ ./app
T::Instances.size() = 1
任何解释这是什么工作?问题似乎与全局变量初始化有关,但我仍然看不到发生了什么。
使用 g++ (GCC) 5.3.1
BR,
........................
在回答昆汀的评论时: 是的,我知道这应该与静态初始化有关,但我仍然不明白这是怎么发生的。 (我不是在 https://isocpp.org/wiki/faq/ctors#static-init-order 的情况下,其中一个编译单元正在调用一个未初始化的对象,因为它在另一个编译单元中找到,至少不是直接调用)。
我还可以在 main.cc 文件中添加一个 T 对象:
#include <iostream>
/*static*/ std::set<T*> T::Instances;
+T main_obj(__FILE__);
int main() {
std::cout << "T::Instances.size() = " << T::Instances.size() << std::endl;
我仍然会崩溃,这里我的理解是我们在当前编译单元中已有的对象上调用静态函数(应该正确初始化)。所以我们至少不直接依赖于在 d.cc 文件中找到的对象。 我再次坚信这与静态初始化有关,但我没有清楚地看到它的解释。 (我们调用其静态成员的对象应该已经初始化)