1. 程式人生 > >設計類、單例模式

設計類、單例模式

1.請設計一個類,該類只能在堆上建立物件

    方法:將類的建構函式和拷貝建構函式宣告為私有,防止別人呼叫拷貝在棧上生成物件

               提供一個靜態的成員函式,在該靜態成員函式中完成堆物件的建立

class heaponly
{
public:
	static heaponly*getheap()
	{
		return new heaponly;
	}
private:
	heaponly()    //構造私有
	{}
	heaponly(const heaponly&);  //拷貝構造私有
};
int main()
{
	heaponly* p1 = heaponly::getheap();
	//heaponly p2;
	//heaponly p3(*p1);
	return 0;
}

2.設計一個類,該類只能在棧上建立物件

class stackonly
{
public:
	static stackonly getonly()
	{
		stackonly obj;
		return obj;
	}
	void print()
	{
		cout << "haha" << endl;
	}
private:       
	stackonly()    //建構函式私有,防止在外部用new建立物件
	{}             //拷貝構造就在棧上,所以拷貝構造不用私有
	//stackonly(const stackonly&) = delete;
};
int main()
{
	stackonly obj = stackonly::getonly();
	obj.print();
	//stackonly* p = new stackonly;
	return 0;
}

    另外還有一種方式,這種方式並不完全正確

    方法:只要將new的功能遮蔽掉就可以,遮蔽operator new

class stack
{
public:
	stack()
	{}
private:
	void* operator new(size_t size);
	void operator delete(void* p);
};
//stack s3;   在資料段
int main()
{
	stack s1;
	//stack s2 = new stack;
	return 0;
}

這段程式碼中  在全域性區建立的S3物件,S3在資料段,並不在棧上

單例模式:

    一個類只能建立一個物件,即單例模式,該模式可以保證系統中該類只有一個例項,並提供一個訪問它的

    全域性訪問點,該例項被所有程式模組共享

    例如:在某個伺服器程式中該伺服器的配置資訊存放在一個檔案中,這些配置資料由一個單例物件統一讀取,然後

               服務程序中的其他物件再通過這個單例物件獲取這些配置資訊,這種方式簡化了在複雜環境下的配置管理

1.餓漢模式

    就是說不管你用不用,程式啟動時就建立一個唯一的例項物件

    優點:簡單明瞭,無需關注執行緒安全問題

    缺點:如果在一個大環境下使用了過多的餓漢單例,則會生產出過多的例項物件,無論你是否要使用他們

class Singleton
{
public:
	static Singleton* GetInstance()
	{
		return &m_instance;
	}
	
private:
	Singleton()
	{};
	Singleton(const Singleton&) = delete;
	Singleton& operator=(Singleton const&);

	static Singleton m_instance;
};
Singleton Singleton::m_instance;
int main()
{
	Singleton *p1 = Singleton::GetInstance();
	return 0;
}

懶漢模式:

    如果單例物件構造十分耗時或者佔用很多資源,比如載入外掛,讀取檔案...有可能該物件程式執行時用不到

    就要在程式一開始進行初始化,就會導致程式啟動時非常緩慢,這種情況使用懶漢模式(延遲載入)更好

    優點:延時載入,用的時候才會產生物件

    缺點:需要保證同步,付出效率的代價。

class Singleton
{
public:
	static Singleton* Getstance()
	{
		//加鎖
		if (m_pInstance == nullptr)
		{
			m_mtx.lock();
			if (m_pInstance == nullptr)
			{
				m_pInstance = new Singleton;
			}
			m_mtx.unlock();
		}
		return m_pInstance;
	}
	//實現一個內嵌垃圾回收類
	class CGarbo{
	public:
		~CGarbo(){
			if (m_pInstance)
				delete m_pInstance;
		}
	};
	//定義一個靜態成員變數,程式結束時,系統會自動呼叫它的解構函式從而釋放單例物件
	static CGarbo Garbo;
private:
	Singleton(){};
	Singleton(const Singleton&) = delete;
	Singleton&operator=(const Singleton&) = delete;
	static Singleton* m_pInstance;
	static mutex m_mtx;
};
Singleton* Singleton::m_pInstance = nullptr;//單例物件指標
mutex Singleton::m_mtx;                     //互斥鎖
Singleton::CGarbo Garbo;