c++ - 使用全局对象静态成员时出现段错误

标签 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

./应用

运行命令时出现段错误,回溯如下:

$ ./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 文件中找到的对象。 我再次坚信这与静态初始化有关,但我没有清楚地看到它的解释。 (我们调用其静态成员的对象应该已经初始化)

最佳答案

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

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

并将其从 main.cc 中删除.

关于c++ - 使用全局对象静态成员时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36981210/

相关文章:

c++ - 使用 GCC 编译 .CPP

c++ - 使用 g++ 时使用 extern "C"{ 对 C++ 代码的影响

C++ Boost Asio - 如何检测断开连接并列出所有事件连接

c++ - 在 Visual Studio 2019 中捕获 std::exception 时,请参阅对函数模板实例化消息的引用

python - 类型映射资源以及将列表转换为 vector (以及反之)

c++ - 使用迭代器排序列表不会对最后一个元素 C++ 进行排序

c++ - 在 C 或 C++ 中的位图上高效执行 bool 表达式

c++ - 让编译器根据架构选择乘法算法

c++ - LVM_INSERTITEM 在 vi​​sta/W7 中非常慢

c++ - 通过服务器将对象传递给客户端