C++ 全局构造函数调用的顺序
来源:互联网 发布:网络骗局麻将 编辑:程序博客网 时间:2024/06/01 10:09
C++的全局类和静态类的构造函数是在main函数之前调用的。但是,不同的类的构造函数以什么顺序调用呢?
对于g++编译器来说,这个顺序是由链接时,文件顺序决定的。
我们用一个例子来说明这一点。
我们有3个文件:t1.h, t1.cpp和tt1.cpp,内容分别是
t.h
#ifndef T_H#define T_H#include <stdio.h>class A {public: A();};class B {public: B(){ a_ = NULL; } void setA(A* a) { a_ = a; } A * a() { return a_; } static B _b;private: A *a_;};extern A *g_a;#endif
tt.cpp
#include "t.h"B B::_b;A *g_a = NULL;A::A(){B::_b.setA(this);g_a = this;}t.cpp
#include "t.h"A a;int main(){printf("a=%p, b.a=%p, g_a=%p\n", &a, B::_b.a(), g_a);}t.h定义了类A和B,其中,在A的构造中,A将自己的指针付给B::_b.a_和g_a。
那么,如果以这样的顺序编译
g++ -o t tt.cpp t.cpp执行 ./t,得到的结果是
a=0x804a024, b.a=0x804a024, g_a=0x804a024这正是我们期望的结果。
如果,按照这样的顺序编译
g++ -o t t.cpp tt.cpp得到的结果是
a=0x804a01c, b.a=(nil), g_a=0x804a01c
那么,为什么先编t.cpp,在编tt.cpp,会得到b.a的结果为null呢?
这应该和ELF文件的格式有关系。
在C/C++语言中,全局变量、静态变量将被放在global数据段,当elf文件被加载到系统中时,global段的数据直接被映射到内存中。
但是,对于C++来说,全局和静态类对象,还必须调用构造函数,这些构造函数的调用,就被放在了init段。这个段是一个代码段,在elf被载入时被执行。
那么,很自然,g++按照链接的顺序,依次把全局类对象的构造放在了init段中。
于是,上面由于t.cpp先被链接,tt.cpp后被链接,因此,a的构造函数就先于B::b_的构造函数调用。 这样,当A::A()被调用时,B::b_::a_的值就被设置为a的指针。
当B::B()被调用时,a_的值被初始化为NULL。
于是,最终的输出结果,b.a=(nil)。
这说明,在C++内部,在全局构造函数中,访问其他全局或者静态变量,其结果是不可预知的。
要解决这个问题,我们使用指针变量。例如,例子中的g_a。
指针变量是一个变量而不是类对象,因此当elf文件被映射到内存中时,g_a的变量值就已经确定,无需额外的代码执行。因此,这可以保证在任意时刻访问g_a变量,都可以得到正确的值。
- C++ 全局构造函数调用的顺序
- 【c++】构造函数调用顺序的研究
- 构造函数的调用顺序
- 看C++中构造函数的调用顺序
- 全局对象构造函数的调用时机
- 建立全局和局部对象时,不同的构造函数和析构函数的调用顺序
- 构造函数调用顺序
- 构造函数调用顺序
- 构造函数调用顺序
- 构造函数调用顺序
- 关于构造函数的调用顺序
- 类的构造函数调用顺序是什么?
- 关于构造函数的调用顺序
- Java构造函数的调用顺序
- 派生类构造函数的调用顺序
- 关于构造函数的调用顺序
- C++构造函数的调用顺序
- 派生类构造函数的调用顺序
- Unity3D中的预制件(Prefab)的创建和使用说明!!!
- Android开发之Ubuntu上Eclipse不显示手机设备
- BT17无线网一键破解,一键式破解WPA,WPA2,AES不再是梦想
- 注重实效的程序员(The Pragmatic Programmer)
- cocos2d-x资料收集
- C++ 全局构造函数调用的顺序
- transaction manager has disabled its support for remote/network transactions. 该伙伴事务管理器已经禁止了它对远程/网络事务
- Jetty 的工作原理以及与 Tomcat 的比较
- 新浪微博技术架构问题解析
- 汇编语言程序设计04-07课程笔记
- Android中Path类的lineTo方法和quadTo方法画线的区别
- Oracle 10G手工创建数据库(Helloblock写作)
- ruby入门练习之String对象
- 使用GreenDroid开源项目