今天廢話不多說,直接進入主題。
full_ptr製作背景:C++auto_ptr指針不做解釋,shared_ptr是引用計數智能指針,它可以幫助你託管你的內存,但在有循環引用的地方比如循環鏈表它就會失效,需要利用week_ptr進行配合使用,相當麻煩和不智能,因此作者興趣之作衍生出了full_ptr來解決shader_ptr的問題。
使用並介紹功能:
這個是測試類,用來給full_ptr測試使用。
class test {
public:
test(char c):c(c) {}
void show()
{
std::cout << "調用了打印函數:" << c << std::endl;
}
~test()
{
std::cout << "刪除:" << c << std::endl;
}
private:
char c;
};
創建full指針a並保存test("a"),然後b也保存a指向的空間,c保存test("c"),然後開始。
c也保存a指向的空間,這時test("c")沒有被其他full引用會被釋放,現在3個full都指向了test("a")。
a和b指針full都打印一下是一樣的,然後把a賦值爲空沒有回收test("a"),把b賦值爲空也沒有回收test("a"),最後函數執行完後回收了c後也回收了test("a")。
循環鏈表示例:
這段代碼是一個簡單的鏈表結構
template<typename T>
class p1
{
public:
p1(full_ptr<T> & data) :_data(&data)
{
}
p1<T> * next;
full_ptr<T> * _data;
};
創建一個full並賦值test('a'),然後創建兩個結點f1和f2都保存full指針,並將f1和f2互相引用,然後打印一下內容,最後函數執行結束後test('a')被回收了。這裏纔是本次文章的重點,如果這裏換成shared_ptr是不能回收test('a')的。
實現原理:
這段是核心代碼,這個類用來保存需要託管的堆空間對象,它有一個count引用計數,用來做被引用計數,當計數爲0虛構所保存的堆空間,同時也虛構自己。
template<typename T>
class _ptr
{
public:
_ptr(T & t) :_data(&t){ count = 0; }
T & GetData()
{
return *_data;
}
void operator++(int){ count++; }
void operator--(int)
{
if (--count <= 0)
{
delete _data;
delete(this);
}
}
private:
int count;
T * _data;
};
father_ptr其實沒什麼用,用途就是繼承它的類纔可以使用_ptr。
class father_ptr
{
public:
template<typename T>
class _ptr
{
。。。
};
};
任何解決shared的問題光靠_ptr肯定不行的,因此就多了一個維護類full_ptr。
在給full賦值的時候都會new一個_ptr並讓它來保存傳進來的空間,然後full來維護_ptr
當出現另外一個full引用自己(full1 = full2)操作時,full2會將_ptr引用的空間也給full1的_ptr引用
不管哪個full自己被回收了都會在虛構函數裏面給_ptr進行計數減1,就這樣,就算外面結構是網狀的,只要有一個full被刪除都會使_ptr減1,直到_ptr爲0時代表沒有full維護它了自己回收了自己。
最後後續作者可能會寫個垃圾回收系統。。。。。
template<typename T>
class full_ptr : public father_ptr
{
public:
/*4個構造函數,這些都是賦值使用的
每個構造函數裏都會new_ptr進行託管*/
full_ptr(T * t)
{
m_ptr = new _ptr<T>(*t);
(*m_ptr)++;
}
full_ptr(T && t)
{
m_ptr = new _ptr<T>(*(new T(t)));
(*m_ptr)++;
}
full_ptr(T & t)
{
m_ptr = new _ptr<T>(*(new T(t)));
(*m_ptr)++;
}
full_ptr(const full_ptr & ptr)
{
if (m_ptr != nullptr)
{
(*m_ptr)--;
}
m_ptr = ptr.m_ptr;
(*m_ptr)++;
}
/*重載->用來可以直接使用full_ptr使用被保存的對象*/
T * operator->()
{
return &m_ptr->GetData();
}
/*引用另外一個full所引用的值*/
void operator=(full_ptr & ptr)
{
if (m_ptr != nullptr)
{
(*m_ptr)--;
}
m_ptr = ptr.m_ptr;
(*m_ptr)++;
}
/*如果賦值爲nullptr就將_ptr計數減1*/
void operator=(void * ptr)
{
if (ptr == nullptr)
{
(*m_ptr)--;
m_ptr = nullptr;
}
}
_ptr<T> * GetData()
{
return m_ptr;
}
/*刪除*/自己也將_ptr計數減1*/
~full_ptr()
{
if (m_ptr != nullptr)
{
(*m_ptr)--;
}
}
private:
_ptr<T> * m_ptr;
};
完整源碼:
class father_ptr
{
public:
template<typename T>
class _ptr
{
public:
_ptr(T & t) :_data(&t){ count = 0; }
T & GetData()
{
return *_data;
}
void operator++(int){ count++; }
void operator--(int)
{
if (--count <= 0)
{
delete _data;
delete(this);
}
}
private:
int count;
T * _data;
};
};
template<typename T>
class full_ptr : public father_ptr
{
public:
full_ptr(T * t)
{
m_ptr = new _ptr<T>(*t);
(*m_ptr)++;
}
full_ptr(T && t)
{
m_ptr = new _ptr<T>(*(new T(t)));
(*m_ptr)++;
}
full_ptr(T & t)
{
m_ptr = new _ptr<T>(*(new T(t)));
(*m_ptr)++;
}
full_ptr(const full_ptr & ptr)
{
if (m_ptr != nullptr)
{
(*m_ptr)--;
}
m_ptr = ptr.m_ptr;
(*m_ptr)++;
}
T * operator->()
{
return &m_ptr->GetData();
}
void operator=(full_ptr & ptr)
{
if (m_ptr != nullptr)
{
(*m_ptr)--;
}
m_ptr = ptr.m_ptr;
(*m_ptr)++;
}
void operator=(void * ptr)
{
if (ptr == nullptr)
{
(*m_ptr)--;
m_ptr = nullptr;
}
}
_ptr<T> * GetData()
{
return m_ptr;
}
~full_ptr()
{
if (m_ptr != nullptr)
{
(*m_ptr)--;
}
}
private:
_ptr<T> * m_ptr;
};