使用全局对象静态成员

时间:2016-05-02 11:21:20

标签: c++

有人可以帮助理解以下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文件中的对象。 我再次强烈认为这与静态初始化有关,但我没有清楚地看到它的解释。 (我们称之为静态成员的对象应该已经初始化)

1 个答案:

答案 0 :(得分:0)

您应该在static std::set<T*> Instances;中定义d.cc

#include "common.h"
#include <set>
std::set<T*> T::Instances;
T d(__FILE__);

将其从main.cc删除。