文章目錄
- 0 背景
- 1 講解
- 1.1 淺層拷貝句柄類
- 1.2 淺、深層結合句柄類
- 2 完整代碼示例
0 背景
在C++2.0中其實很多地方都用到了這種思想,如智能指針(share_ptr)、右值引用等。它實際上就是一個模版指針類,封裝了指向類的指針,當進行指派操作時,是拷貝一個新對象指派或者是指向同一個對象。在指向同一個對象時,為了防止對象被還有指向該對象的指針就被删除,設定引用計數,當指向的對象的指針需要修改該對象,而其他指針不需要使用到修改的對象時,可以拷貝一個新的對象,讓修改的指針指向。
這個類的好處在于可以避免大量不必要的記憶體管理和資料複制,提高了程式運作效率。
1 講解
1.1 淺層拷貝句柄類
兩個成員變量,指向對象的指針,引用計數的指針
template <typename T>
class ReferenceHandle{
private:
T* m_p;
std::size_t* m_refptr;
};
構造函數:
//對象指針指向空指針,引用計數設定為1
ReferenceHandle():m_p(nullptr),m_refptr(new std::size_t(1)){}
//對象指針指向對象,引用計數設定為1
ReferenceHandle(T* t):m_p(t),m_refptr(new std::size_t(1)){}
拷貝構造函數:
//對象指針指向同一個對象,引用計數加1
ReferenceHandle(const ReferenceHandle& h):m_p(nullptr),m_refptr(h.refptr){
++*m_refptr;
}
指派構造函數:
//為了防止自我指派時,
//還沒有指派就提前把對象删除了,這裡采取了先對對象引用計數+1
ReferenceHandle&operator=(const ReferenceHandle& h){
++*m_refptr;
if(--*m_refptr==0){
delete m_refptr;
delete m_p;
}
m_refptr = h.m_refptr;
m_p = h.m_p;
return *this;
}
析構函數:
//如果引用計數為0,則删除指向的對象和引用計數對象
~ReferenceHandle(){
if(--*m_refptr==0){
delete m_p;
delete m_refptr;
}
}
bool運算符函數:
//如果指針與實際對象關聯,則會傳回true,否則傳回false
operator bool() const{ return m_p;}
operator*和operator->操作賦函數:
//用于通路指針指向的對象
T&operator*()const {
if(m_p) return *m_p;
throw std::runtime_error("unbound Hanlde");
}
T*operator->()const {
if(m_p) return m_p;
throw std::runtime_error("unbound Hanlde");
}
1.2 淺、深層結合句柄類
成員對象:指向對象的指針、引用計數指針
template <typename T>
class Ptr{
private:
T* m_p;
std::size_t* m_refptr;
};
拷貝構造函數:
ReferenceHandle():m_p(nullptr),m_refptr(new std::size_t(1)){}
ReferenceHandle(T* t):m_p(t),m_refptr(new std::size_t(1)){}
ReferenceHandle(const ReferenceHandle& h):m_p(nullptr),m_refptr(h.refptr){
++*m_refptr;
}
指派構造函數:
ReferenceHandle&operator=(const ReferenceHandle& h){
++*m_refptr;
if(--*m_refptr==0){
delete m_refptr;
delete m_p;
}
m_refptr = h.m_refptr;
m_p = h.m_p;
return *this;
}
析構函數:
~ReferenceHandle(){
if(--*m_refptr==0){
delete m_p;
delete m_refptr;
}
}
操作符函數:
operator bool() const{ return m_p;}
T&operator*()const {
if(m_p) return *m_p;
throw std::runtime_error("unbound Hanlde");
}
T*operator->()const {
if(m_p) return m_p;
throw std::runtime_error("unbound Hanlde");
}
複制拷貝成員函數:
當指向的類是自己建立的類時,使用此函數:
//當存在會改變引用值的情況時,配置設定新對象
void makeUnique(){
if(*m_refptr != 1){
--*m_refptr;
m_refptr = new size_t(1);
//成員函數版本
m_p = m_p?m_p->clone():0;
//全局函數版本
// m_p = m_p?clone(m_p):0;
}
}
複制拷貝非成員函數:
//非成員函數版本
//特化一個模版來處理成員函數中沒有clone()的情況(即沒有T::clone())
template <class T>T* clone(const T* tp){
return tp->clone();
}
template <>
std::vector<char>* clone(const std::vector<char>* vp){
return new std::vector<char>(*vp);
}
void makeUnique(){
if(*m_refptr != 1){
--*m_refptr;
m_refptr = new size_t(1);
//成員函數版本
m_p = m_p?m_p->clone():0;
//全局函數版本
// m_p = m_p?clone(m_p):0;
}
}
2 完整代碼示例
#include <iostream>
using std::cout; using std::endl;
#include <vector>
#include <stdexcept>
//淺層拷貝句柄類
template <typename T>
class ReferenceHandle{
public:
ReferenceHandle():m_p(nullptr),m_refptr(new std::size_t(1)){}
ReferenceHandle(T* t):m_p(t),m_refptr(new std::size_t(1)){}
ReferenceHandle(const ReferenceHandle& h):m_p(nullptr),m_refptr(h.refptr){
++*m_refptr;
}
ReferenceHandle&operator=(const ReferenceHandle& h){
++*m_refptr;
if(--*m_refptr==0){
delete m_refptr;
delete m_p;
}
m_refptr = h.m_refptr;
m_p = h.m_p;
return *this;
}
~ReferenceHandle(){
if(--*m_refptr==0){
delete m_p;
delete m_refptr;
}
}
operator bool() const{ return m_p;}
T&operator*()const {
if(m_p) return *m_p;
throw std::runtime_error("unbound Hanlde");
}
T*operator->()const {
if(m_p) return m_p;
throw std::runtime_error("unbound Hanlde");
}
private:
T* m_p;
std::size_t* m_refptr;
};
//非成員函數版本
//特化一個模版來處理成員函數中沒有clone()的情況(即沒有T::clone())
template <class T>T* clone(const T* tp){
return tp->clone();
}
template <>
std::vector<char>* clone(const std::vector<char>* vp){
return new std::vector<char>(*vp);
}
//淺層、深層結合句柄類
template <typename T>
class Ptr{
public:
//當存在會改變引用值的情況時,配置設定新對象
void makeUnique(){
if(*m_refptr != 1){
--*m_refptr;
m_refptr = new size_t(1);
//成員函數版本
// m_p = m_p?m_p->clone():0;
//全局函數版本
m_p = m_p?clone(m_p):0;
}
}
Ptr():m_p(nullptr),m_refptr(new std::size_t(1)){}
Ptr(T* t):m_p(t),m_refptr(new std::size_t(1)){}
Ptr(const Ptr& h):m_p(nullptr),m_refptr(h.m_refptr){
++*m_refptr;
}
Ptr&operator=(const Ptr& h){
++*m_refptr;
if(--*m_refptr==0){
delete m_refptr;
delete m_p;
}
m_refptr = h.m_refptr;
m_p = h.m_p;
return *this;
}
~Ptr(){
if(--*m_refptr==0){
delete m_p;
delete m_refptr;
}
}
operator bool() const{ return m_p;}
T&operator*()const {
if(m_p) return *m_p;
throw std::runtime_error("unbound Hanlde");
}
T*operator->()const {
if(m_p) return m_p;
throw std::runtime_error("unbound Hanlde");
}
private:
T* m_p;
std::size_t* m_refptr;
};
class Core{
friend class ReferenceHandle<Core>;
virtual Core* clone(){
return new Core(*this);
}
public:
virtual ~Core(){}
virtual void test(double d, double d2 = 0){cout<<"test(double d1, double d2=0)"<<endl;}
};
class Derive :public Core{
friend class ReferenceHandle<Core>;
public:
virtual Derive* clone(){
return new Derive(*this);
}
void test(double d1, double d2){cout<<"test(double d1, double d2)"<<endl;}
typedef std::vector<char>::size_type size_type;
//成員函數版本
char&operator[](size_t i){
m_data.makeUnique();
return (*m_data)[i];
}
private:
Ptr<std::vector<char>> m_data;
};
int main(){
// Handle<Core> c(new Derive);
std::vector<ReferenceHandle<Core>> handle;
ReferenceHandle<Core> h, h2;
h = new Core;
h2 = h;
return 0;
}