[英]C++ Global Object Constructor Vs. main Call Sequence
我从c ++构造函数中收到奇怪的行为,请澄清一下。 最近,我想利用Singleton模式。 在网上搜索示例并修改代码以满足我的需求后,我遇到了意外的行为。 只需在main()开始之前调用这些构造函数即可。 为了节省您阅读代码的时间,这是4个类。 我只是有main.cpp,First.cpp,Second.cpp,Third.cpp和Singleton.cpp。
在main.cpp中
int main()
{
cout << "Inside main()" << endl;
cout<<"val = "<<Singleton::Instance()->callThem()<<endl;
delete Singleton::Instance();
return 0;
}
调用顺序为:main()-> Singleton :: callThem()-> First :: callFirst()-> Second :: callSecond()-> Third :: callThird()
单例
#include "singleton.h"
#include <iostream>
First first; //source of the problem
Singleton::Singleton()
{
std::cout<<"Singleton Constructor"<<std::endl;
}
Singleton::~Singleton()
{
std::cout<<"Singleton Destructor"<<std::endl;
}
Singleton* Singleton::m_pInstance = NULL;
Singleton* Singleton::Instance()
{
if (!m_pInstance)
{
m_pInstance = new Singleton;
}
return m_pInstance;
}
int Singleton::callThem()
{
return first.callFirst();
}
输出如下:
Third Constructor
Second Constructor
First Constructor
Inside main()
Third Constructor
Second Constructor
First Constructor
Singleton Constructor
val = 3
Singleton Destructor
First Destructor
Second Destructor
Third Constructor
First Destructor
Second Destructor
Third Constructor
在Inside main()
之前如何调用构造函数? main()不在执行开始的地方吗?
如果我先删除First first; //source of the problem
First first; //source of the problem
,打印出来的第一行是Inside main()
,没有在main()之前调用的构造函数。 非常感谢您的澄清。
在运行main()
之前, 将构造并初始化全局变量。
如果您正在寻找单例模式,建议您使用:
template <typename T>
class Singleton {
public:
static T *GetInstance() {
static T value;
return &value;
};
};
int main() {
int *x = Singleton<int>::GetInstance();
}
不,全局对象是在main
之前(或至少在main中的代码执行之前构建的-编译器会在程序员提供的第一个代码之前插入一个“初始化全局对象”的调用,但是如今,大多数编译器都在这样做)通过具有由编译器/链接器构建的“ pre-main”函数]。
还要注意,不同翻译单元的全局构造函数之间的顺序是完全未定义的-该顺序是在声明的特定翻译单元内定义的。
这确实是一件令人讨厌的事情,但这也是一个很难以更好的方式解决的问题。 最好的解决方案是在需要时按需构造对象,而不是使用全局变量-即使这也可能有些棘手。
可能使Singleton
返回shared_ptr
可以解决问题-我使用了类似的方法来使锁保持活动状态,其中使用该锁的每个位置都具有共享指针的副本,因此仅当最后一个用户使用时才如此。锁不见了,锁本身是否被删除。 这五行更改加上30行注释,解释了为什么这样做是必要的,以及几乎一样长的提交消息,因为这是棘手的内容,很容易被某人认为“啊,但是我们可以删除其中的一些内容”破坏。 ”。 [不是说shared_ptr
很棘手,而是使用shared_ptr
而不是单个全局变量IS]
非常感谢您的澄清。
一种简单易懂的方法来控制您认为您可能希望全局访问的对象的初始化(ctor)序列可能是...
一种。 替换以下任何“ T类”的全局实例
T1 theT1; // a global instance, with no control of initialization sequence
至
T1* theT1 = nullptr; // a global instance ptr, constructed when you want.
对每个全局对象重复此操作。
b。 在main()之后,可能在main()之前,但肯定在需要对象之前,显式初始化句柄。
请注意,关于在多线程面前创建单例的技术有很多文献。 单例的书籍版本不是线程安全的。 (我认为作者用一句话说,模式书中没有一种模式是线程安全的。)
明确控制ctor序列极大地增加了您测试出厂产品的信心。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.