揭示C++中全局类变量的构造与析构顺序
作者:网络转载 发布时间:[ 2013/1/31 11:17:11 ] 推荐标签:
ldscript
/* Script for ld --enable-auto-import: Like the default script except
read only data is placed into .data */
SECTIONS
{
/* Make the virtual address and file offset synced if the
alignment is lower than the target page size. */
. = SIZEOF_HEADERS;
. = ALIGN(__section_alignment__);
.text __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) :
{
*(.init)
*(.text)
*(SORT(.text$*))
*(.text.*)
*(.glue_7t)
*(.glue_7)
___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*)); LONG (0);
___DTOR_LIST__ = .; __DTOR_LIST__ = . ;
LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*)); LONG (0);
*(.fini)
/* ??? Why is .gcc_exc here? */
*(.gcc_exc)
PROVIDE (etext = .);
*(.gcc_except_table)
}
……
}
代码4
请注意脚本中的18~21行。这几行的作是将所有程序文件(包括目标文件和库文件)中的全局变量构造和析构函数的函数指针放入对应的数组中。从C++语言的角度来看,__CTOR_LIST__数组被用于存放全局类变量构造函数的指针,而__DTOR_LIST__数组被用于存放析构函数的。注意,对于构造函数数据,它是由各程序文件中的.ctors、.ctor和包含.ctors.的程序段组成的。此外,两个数据的第一项一定是-1,后一项则一定是0。
通过查看gcc的源代码(g++的实现也位于其中),可以从gbl-ctors.h中看到两个数组的声明,从libgcc2.c文件中了解各全局类变量的构造与析构函数是如何被调用的,如图 5所示。注意,这里示例的代码出于简化的目的有所删减。
gbl-ctors.h
typedef void (*func_ptr) (void);
extern func_ptr __CTOR_LIST__[];
extern func_ptr __DTOR_LIST__[];
#define DO_GLOBAL_CTORS_BODY
do {
unsigned long nptrs = (unsigned long) __CTOR_LIST__[0];
unsigned i;
if (nptrs == (unsigned long)-1)
for (nptrs = 0; __CTOR_LIST__[nptrs + 1] != 0; nptrs++);
for (i = nptrs; i >= 1; i--)
__CTOR_LIST__[i] ();
} while (0)
libgcc2.c
void __do_global_dtors (void)
{
static func_ptr *p = __DTOR_LIST__ + 1;
while (*p) {
p++;
(*(p-1)) ();
}
}
void __do_global_ctors (void)
{
DO_GLOBAL_CTORS_BODY;
atexit (__do_global_dtors);
}
代码5
结合图中的两个文件可以知晓,全局类变量的构造函数是通过__do_global_ctors()函数来调用的。从DO_GLOBAL_CTORS_BODY宏的实现来看,在11和12行获得数组中构造函数的个数,并在13和14行以逆序的方式调用每一个构造函数。__do_global_ctors()函数在后调用C库的atexit()函数注册__do_gloabl_dtors()函数,使得程序退出时该函数得以被调用。
从__do_global_dtors()函数的实现来看,各全局变量的析构函数是顺序调用的,与调用构造函数的顺序是相反的。这保证做到“先构造的全局类变量后析构。” 对__do_gloable_ctors() 和__do_gloable_dtors()函数的调用是由C++语言的环境构建代码来调用的。总的说来,它们分别在进入和退出main()函数时被调用。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11