Mas*_*ari 16 c++ memory singleton static dynamic-memory-allocation
我的具体问题是,在C++中实现单例类时,以下两个代码之间在性能,方面问题或其他方面存在实质性差异:
class singleton
{
// ...
static singleton& getInstance()
{
// allocating on heap
static singleton* pInstance = new singleton();
return *pInstance;
}
// ...
};
Run Code Online (Sandbox Code Playgroud)
还有这个:
class singleton
{
// ...
static singleton& getInstance()
{
// using static variable
static singleton instance;
return instance;
}
// ...
};
Run Code Online (Sandbox Code Playgroud)
(请注意,基于堆的实现中的解除引用不应该影响性能,因为AFAIK没有为解除引用生成额外的机器代码.似乎只需要语法来区分指针.)
更新:
我有一些有趣的答案和评论,我试着在这里总结一下.(建议有兴趣的人阅读详细的答案.):
static singleton& getInstance() {
static std::auto_ptr<singleton> instance (new singleton());
return *instance.get();
}
Run Code Online (Sandbox Code Playgroud)
使用动态分配的单例比静态单例变量"更懒惰",如后一种情况,单例对象所需的内存(始终?)在进程启动时保留(作为加载程序所需的整个内存的一部分)并且只调用单例构造函数被推迟到getInstance()调用时.这可能sizeof(singleton)很重要.
两者都是C++ 11中的线程安全的.但是对于早期版本的C++,它是特定于实现的.
动态分配情况使用一个间接级别来访问单例对象,而在静态单例对象情况下,确定对象的直接地址并在编译时进行硬编码.
PS:根据@TonyD的答案,我已经更正了我在原帖中使用的术语.
该new版本显然需要在运行时分配内存,而非指针版本具有在编译时分配的内存(但两者都需要做相同的构造)
该new版本将不会在程序终止时调用该对象的析构函数,但非new版本:您可以使用智能指针,以纠正这种
在C++ 03下,它的实现定义是否是线程安全的.(我相信GCC往往是,而Visual Studio往往不会 - 评论确认/纠正赞赏.)
在C++ 11下,它是安全的:6.7.4"如果控制在初始化变量时同时进入声明,则并发执行应等待初始化完成." (没有递归).
讨论重新编译时与运行时分配和初始化
从你的汇总和一些评论的方式来看,我怀疑你并没有完全理解静态变量的分配和初始化的微妙方面....
假设你的程序有3个本地静态32位int的S - a,b以及c-在不同的功能:编译器可能编译二进制文件告诉操作系统加载器离开3x32位= 12个字节的内存对于那些静.编译器决定每个变量的偏移量:它可以放在a数据段的偏移量1000十六进制,b1004和c1008.当程序执行时,OS加载器不需要为每个分别分配内存 -所有它知道的是总共12个字节,它可能会或可能不会被特别要求0初始化,但它可能想要做任何事情以确保进程无法看到来自其他用户程序的内存内容.程序中的机器代码指令通常将对偏移1000,1004,1008进行硬编码以便访问a,b并且c因此在运行时不需要分配那些地址.
动态存储器分配是,所述不同的指针(比如p_a,p_b,p_c)将给出如刚刚描述在编译时地址,但额外的:
a,b和c)(通常在静态函数首次执行时,但编译器允许按照我对其他答案的评论更早地执行),以及
sbreak()) - 出于安全原因操作系统通常会将其清除a,b并且c必须被复制回指针p_a,p_b和p_c.这种动态方法显然更复杂.