有人可以帮助理解以下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
./应用
运行命令我得到一个seg错误,带有以下回溯:
$ ./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
程序运行时没有seg错误。
$ 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文件中的对象。 我再次强烈认为这与静态初始化有关,但我没有清楚地看到它的解释。 (我们称之为静态成员的对象应该已经初始化)
答案 0 :(得分:0)
您应该在static std::set<T*> Instances;
中定义d.cc
:
#include "common.h"
#include <set>
std::set<T*> T::Instances;
T d(__FILE__);
将其从main.cc
删除。