新聞中心
- 特殊類的設計
- 1.不能被拷貝的類
- 2.只能在堆上創(chuàng)建對象的類
- 3.只能在棧上創(chuàng)建的類
- 單例模式
- 1.餓漢模式
- 2.懶漢模式
- 3.單例對象的釋放問題
在我們上一章的unique中就是讓我們的對象不能被拷貝。
我們這里可以將賦值和拷貝構造都設置為私有屬性。
class CopyBan
{// ...
private:
Copy(const Copy&);
Copy& operator=(const Copy&);
//...
};
2.只能在堆上創(chuàng)建對象的類#includeclass HeapOnly
{//將析構函數(shù)私有
private:
~HeapOnly()
{}
private:
int _a;
};
int main() {HeapOnly hp1;
static HeapOnly hp2;
HeapOnly* ptr =new HeapOnly;
return 0;
}
正常定義的對象我們都需要調用析構函數(shù),如果我們把析構函數(shù)設置成私有,那么我們的上面代碼中的hp1,hp2都會報錯,而我們的ptr因為沒有調用析構函數(shù),所以可以正常編譯通過。
那么我們就需要手動釋放ptr,也就是寫成下面的寫法
#includeusing namespace std;
class HeapOnly
{public:
static void Delete(HeapOnly* p)
{delete p;
}
//將析構函數(shù)私有
private:
~HeapOnly()
{cout<<"heapOnly"<// HeapOnly hp1;
// static HeapOnly hp2;
HeapOnly* ptr =new HeapOnly;
ptr->Delete(ptr);
return 0;
}
或者將構造函數(shù)私有化,采用下面的寫法
#includeusing namespace std;
class HeapOnly
{public:
//提供一個共有的,獲取對象的方式,對象控制是new出來的
static HeapOnly* CreateObject()
{return new HeapOnly;
}
private:
HeapOnly()
:_a(0)
{}
private:
int _a;
};
int main() {// HeapOnly hp1;
// static HeapOnly hp2;
HeapOnly* hp3 =HeapOnly::CreateObject();
delete hp3;
return 0;
}
但是我們還需要防止別人采用拷貝構造的方式在棧上開辟空間,這里我們還需要將拷貝構造和賦值設置成私有的。
#includeusing namespace std;
class HeapOnly
{public:
//提供一個共有的,獲取對象的方式,對象控制是new出來的
static HeapOnly* CreateObject()
{return new HeapOnly;
}
private:
HeapOnly(const HeapOnly& hp)=delete;
HeapOnly& operator=(const HeapOnly& hp)=delete;
HeapOnly()
:_a(0)
{}
private:
int _a;
};
int main() {// HeapOnly hp1;
// static HeapOnly hp2;
HeapOnly* hp3 =HeapOnly::CreateObject();
//拷貝構造的空間在棧上
HeapOnly copy(*hp3);
delete hp3;
return 0;
}
3.只能在棧上創(chuàng)建的類#includeusing namespace std;
class StackOnly
{public:
static StackOnly CreateObj()
{StackOnly st;
return st;
}
// StackOnly(const StackOnly& hp)=delete;
// StackOnly& operator=(const StackOnly& hp)=delete;
void* operator new(size_t n)=delete;
private:
StackOnly()
:_a(0)
{}
private:
int _a;
};
int main() {// StackOnly hp1;
// static StackOnly hp2;
StackOnly hp3 =StackOnly::CreateObj();
//拷貝構造
//因為我們這里一定要傳值返回,然后如果把傳值返回給禁用了,我們這里上面的
//正產的hp3也沒有辦法創(chuàng)建了。
//所以這里的copy(hp3)沒有辦法禁用
StackOnly copy2(hp3); //不好處理,小缺陷
// StackOnly * copy3=new StackOnly(hp3);
return 0;
}
單例模式設計模式:
設計模式(Design Pattern)是一套被反復使用、多數(shù)人知曉的、經過分類的、代碼設計經驗的總結。
使用設計模式的目的:為了代碼可重用性、讓代碼更容易被他人理解、保證代碼可靠性。 設計模式使代碼編寫真正工程化;設計模式是軟件工程的基石脈絡,如同大廈的結構一樣。
單例模式:
一個類只能創(chuàng)建一個對象,即單例模式,該模式可以保證系統(tǒng)中該類只有一個實例,并提供一個訪問它的全局訪問點,該實例被所有程序模塊共享。比如在某個服務器程序中,該服務器的配置信息存放在一個文件中,這些配置數(shù)據由一個單例對象統(tǒng)一讀取,然后服務進程中的其他對象再通過這個單例對象獲取這些配置信息,這種方式簡化了在復雜環(huán)境下的配置管理。
1.餓漢模式JAVA版本的單例模式
餓漢模式–一開始(main函數(shù)之前)就創(chuàng)建出對象
可以使用下面這種生成一個靜態(tài)的對象
//餓漢模式
class MemoryPool
{public:
private:
//構造函數(shù)私有化
MemoryPool()
{}
char* _ptr= nullptr;
//創(chuàng)建一個靜態(tài)的自己的對象
//因為靜態(tài)的對象是存在靜態(tài)區(qū)的,是屬于所有類的
static MemoryPool _inst;//聲明
};
//定義,在類外進行構造
MemoryPool MemoryPool::_inst;
int main()
{// MemoryPool pool1;
//MemoryPool pool2;
}
或者像下面這樣采用指針的形式
#includeusing namespace std;
//餓漢模式
class MemoryPool
{public:
static MemoryPool*GetInstance()
{return _pinst;
}
void* Alloc(size_t n)
{void* ptr= nullptr;
return ptr;
}
void Dealloc(void*ptr)
{}
private:
//構造函數(shù)私有化
MemoryPool()
{}
char* _ptr= nullptr;
//創(chuàng)建一個靜態(tài)的自己的對象
//因為靜態(tài)的對象是存在靜態(tài)區(qū)的,是屬于所有類的
static MemoryPool* _pinst;//聲明
};
//定義,在類外進行構造
MemoryPool* MemoryPool::_pinst=new MemoryPool;
int main()
{// MemoryPool pool1;
//MemoryPool pool2;
void* ptr1=MemoryPool::GetInstance()->Alloc(10);
MemoryPool::GetInstance()->Dealloc(ptr1);
}
2.懶漢模式餓漢模式:
優(yōu)點:簡單,沒有線程安全問題(因為它在main函數(shù)之前就執(zhí)行了,不存在競爭的問題)。
缺點:1、一個程序中,有多個單例,并且有先后創(chuàng)建初始化順序要求時,餓漢無法控制
(比方說A先創(chuàng)建,然后B在創(chuàng)建,這樣是沒有辦法做到的,因為它們都是靜態(tài)成員,我們是沒有辦法確定的。同一個文件中可能誰在前,誰先初始化,但是如果是在多個文件中就不好控制了)
2、餓漢單例模式,初始化任務多的時候,會影響程序的啟動速度。因為我們上面的單例的初始化是在main函數(shù)之前就創(chuàng)建的。
懶漢模式:第一次使用對象再創(chuàng)建實例對象。
#includeusing namespace std;
//餓漢模式
class MemoryPool
{public:
static MemoryPool*GetInstance()
{if(_pinst== nullptr)
{_pinst=new MemoryPool;
}
return _pinst;
}
void* Alloc(size_t n)
{void* ptr= nullptr;
return ptr;
}
void Dealloc(void*ptr)
{}
private:
//構造函數(shù)私有化
MemoryPool()
{}
char* _ptr= nullptr;
//創(chuàng)建一個靜態(tài)的自己的對象
//因為靜態(tài)的對象是存在靜態(tài)區(qū)的,是屬于所有類的
static MemoryPool* _pinst;//聲明
};
//定義,在類外進行構造
MemoryPool* MemoryPool::_pinst=nullptr;
int main()
{// MemoryPool pool1;
//MemoryPool pool2;
void* ptr1=MemoryPool::GetInstance()->Alloc(10);
MemoryPool::GetInstance()->Dealloc(ptr1);
}
3.單例對象的釋放問題優(yōu)點
1、控制順序
2、不影響啟動速度
缺點:
1、相對復雜(線程安全問題)
2、線程安全問題要處理好
1、一般情況下,單例對象不需要釋放。一般整個程序運行期間都可能會用到。
2、單例對象在進程正常結束之后也會資源釋放
3、有些特殊的場景需要釋放,比如單例對象析構時,要進行一些持久化(往文件,數(shù)據庫寫)操作。
我們可以通過定義一個內嵌類型的垃圾回收器來釋放我們的空間
#includeusing namespace std;
//餓漢模式
class MemoryPool
{public:
static MemoryPool*GetInstance()
{if(_pinst== nullptr)
{_pinst=new MemoryPool;
}
return _pinst;
}
void* Alloc(size_t n)
{void* ptr= nullptr;
return ptr;
}
void Dealloc(void*ptr)
{}
// 實現(xiàn)一個內嵌垃圾回收類
class CGarbo {public:
~CGarbo()
{if (_pinst)
delete _pinst;
}
};
private:
//構造函數(shù)私有化
MemoryPool()
{}
char* _ptr= nullptr;
//創(chuàng)建一個靜態(tài)的自己的對象
//因為靜態(tài)的對象是存在靜態(tài)區(qū)的,是屬于所有類的
static MemoryPool* _pinst;//聲明
};
//定義,在類外進行構造
MemoryPool* MemoryPool::_pinst=nullptr;
//定義一個靜態(tài)的全局的回收對象
//在main函數(shù)結束之后,它會調用析構函數(shù),就會釋放單例對象。
static MemoryPool::CGarbo gc;
int main()
{// MemoryPool pool1;
//MemoryPool pool2;
void* ptr1=MemoryPool::GetInstance()->Alloc(10);
MemoryPool::GetInstance()->Dealloc(ptr1);
}
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧
網站名稱:C++【特殊類的設計】【單例設計模式】-創(chuàng)新互聯(lián)
文章路徑:http://fisionsoft.com.cn/article/cesici.html