另类单例xx

#include <iostream>
using namespace std;

class A{
public:
	void ptf(void)
	{
		cout << "test" << endl;
	}
	static A& GetInstance(void)
	{
		return m_a;
	}
private:
	A(void){};
	A(const A&){};

	static A m_a;
}
A A::m_a;

int main(void)
{
	A& a = A::GetInstance();
	a.ptf();
	cout << "sizeof(A) = " << sizeof(A) << " and sizeof(a) = " << sizeof(a) << endl;//sizeof(A) = 1 and sizeof(a) = 1
	getchar();
	return 0;
}

由于A中的成员m_a是静态的,属于类,且具有进程级的声明周期,在构造A对象时,不用管m_a,所以可以构造出A对象。

但是由于其具有进程级的声明周期,在进程启动时,就会分配A对象的内存,如果A成员变量占用较多内存,则会一直占用较多内存。

此类中除了A::m_a没有其他成员。所以sizeof(A) = 1;sizeof(a) = 1;

优化方式是:
一种是使用指针类型的A* A::m_pa;但此种方式依然至少占用一个sizeof(A*)大小内存,即全局区内存占用只多了一个指针所占内存大小。
另外也可以这样定义:

	static A* A::GetInstance2(void)
	{
		static A a;
		return &a;
	}

使用这种方式会在首次调用的时候分配空间。
至于是使用

	static A* A::GetInstance2(void)
	{
		static A a;
		return &a;
	}

还是

	static A* A::GetInstance2(void)
	{
		static A* pa = NULL;
		if(NULL == pa)
		{
			pa = new A;
		}
		return pa;
	}

有差异,懒汉和恶汉模式,一个使用时初始化,一个是启动就初始化了。另外就是一个在栈一个在堆。

至于上面sizeof(A)占用内存为1个字节
参看:C/C++—— C++中一个空对象为什么还要占用一个字节空间

摘要如下:
1.标准对此的确有规定,但没有明确规定空对象一定要是1字节,标准只是规定了对象的大小必须大于0,首先标准中有如下标定“An object is a region of storage. ”。 

2.显然不存在0字节长度的存储区域,这句话隐含了空对象是大于0的,另外还有标定“a most derived object shall have a non-zero size and shall occupy one or more bytes of storage. Base class sub-objects may have zero size. An object of POD contiguous bytes of storage.”,
说明了最终派生对象大小是非0值,其大小可以是1或多个字节,基类子对象可以为0(任何可直接创建的对象都不会为0,如果一个类A是个空类,那么直接创建对象的时候大小为1,如果B类从A类派生并且没有额外的数据成员,那么直接创建B类时大小依然为1,规定对基类子对象可为0的规定使的编译器会进行空基类优化)。
3.最后在关于sizeof操作符中也有相关规定“The size of a most derived class shall be greater than zero ”,可见规定的确规定了空对象大小不能为0的现实,但却不强制其大小一定为1(这为编译器为不同的操作系统进行优化留有余地,比如说在不同字长[8,16,32,64]位CPU下,最有效率的操作数类型都是CPU的字长,那么编译器可以选择机器字长来作为不为0时的最小长度)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值