STL 的 auto_ptr 已經(jīng)棄用, 為了解決手動(dòng)釋放指針內(nèi)存的問(wèn)題, 自定義一個(gè)好使的 AutoPtr 包裝類(lèi), 不足的一點(diǎn)是所有被包裝的類(lèi)必須繼承自 BaseType, 因?yàn)?BaseType 中有當(dāng)前被包裝類(lèi)的對(duì)象的引用計(jì)數(shù)。
每有一個(gè) AutoPtr 對(duì)象的 mPtr 指針指向被包裝類(lèi)的對(duì)象, 那么該被包裝類(lèi)的對(duì)象的引用計(jì)數(shù)就 + 1;每有一個(gè) AutoPtr 對(duì)象析構(gòu), 那么 AutoPtr 對(duì)象的 mPtr 指針指向被包裝類(lèi)的對(duì)象的引用計(jì)數(shù)就 -1, 當(dāng)執(zhí)行AutoPtr 對(duì)象的析構(gòu)函數(shù)發(fā)現(xiàn) mPtr 指針指向的被包裝類(lèi)的對(duì)象的引用計(jì)數(shù)變?yōu)?0 時(shí), 就 delete 掉 mPtr 指針, 釋放被包裝類(lèi)的對(duì)象的內(nèi)存, 從而解決了手動(dòng) delete 釋放內(nèi)存的問(wèn)題。
代碼如下 :
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
using namespace std;
//自己編寫(xiě)智能指針代理類(lèi) AutoPtr
//mTotalAutoPtrCount 目前只能針對(duì)一種 Tp 類(lèi)型
static int mTotalAutoPtrCount = 0; //使用 mCurCount 判斷當(dāng)前是 auto_p1 還是 auto_p2
template<typename Type>
class AutoPtr;
class BaseType{
public:
//AutoPtr * autoPtr;
int curRefCount = 0; //當(dāng)前對(duì)象的 AutoPtr 引用計(jì)數(shù)
BaseType(){
}
};
//如何讓 Type 繼承自 BaseType ?
template<typename Type>
class AutoPtr {
private:
//外部的數(shù)據(jù)
BaseType* mPtr = nullptr;
int curCount = 0;
public:
explicit AutoPtr() throw() {
processCurCount("AutoPtr() Constructor");
}
explicit AutoPtr(BaseType *_p) throw(): mPtr(_p) {
((*_p).curRefCount) ++; //AutoPtr 對(duì)象引用 BaseType 對(duì)象
processCurCount("AutoPtr(BaseType *_p) Constructor");
}
//拷貝構(gòu)造函數(shù) //注意 : 這么寫(xiě)不好使, 必須是 const AutoPtr<Type>& autoPtr 拷貝構(gòu)造函數(shù)才會(huì)執(zhí)行 !
// AutoPtr(const AutoPtr<BaseType>& autoPtr): mPtr(autoPtr.mPtr){
// cout << "*************** Auto CopyConstructor *******************" << endl;
// (autoPtr.value() -> curRefCount) ++;
// processCurCount("AutoPtr CopyConstructor");
// }
//拷貝構(gòu)造函數(shù)
AutoPtr(const AutoPtr<Type>& autoPtr): mPtr(autoPtr.mPtr){
cout << "*************** Auto CopyConstructor *******************" << endl;
(autoPtr.value() -> curRefCount) ++;
processCurCount("AutoPtr CopyConstructor");
}
// ~AutoPtr() {
// count--;
// if(count < 1){
// delete _M_ptr;
// }
// }
~AutoPtr() {
cout << "-------------- ~AutoPtr() Pre ----------"<< endl;
mTotalAutoPtrCount --;
cout << "AutoPtr deConstructor, auto_p" << curCount
<< " mTotalAutoPtrCount = " << mTotalAutoPtrCount << endl << endl;
processMPtr("AutoPtr deConstructor");
cout << "-------------- ~AutoPtr() Back ----------"<< endl;
}
//如果要進(jìn)行 * 號(hào)操作, 那么直接返回里面的 _M_ptr
BaseType* operator*() {
return mPtr;
}
AutoPtr* operator=(AutoPtr& tp) {
cout << "operator=(AutoPtr& tp)" << endl;
(tp.mPtr) -> curRefCount ++;
processMPtr("AutoPtr operator=(AutoPtr& tp)");
mPtr = tp.mPtr;
return this;
}
AutoPtr* operator=(BaseType& tp) {
cout << "operator=(BaseType& tp)" << endl;
tp.curRefCount ++;
processMPtr("AutoPtr operator=(BaseType& tp)");
mPtr = &tp;
return this;
}
Type * value() const {
if(mPtr == nullptr){
return nullptr;
}
return reinterpret_cast<Type*>(mPtr);; //(Type*)(mPtr);
}
private:
void processCurCount(const string& preFix){
printf("processCurCount Pre, preFix = %s, mTotalAutoPtrCount = %d \n", preFix.c_str(), mTotalAutoPtrCount);
mTotalAutoPtrCount ++;
for(int i = 0; i < 10; ++i){
if(mTotalAutoPtrCount == i){
curCount = mTotalAutoPtrCount;
}
}
printf("processCurCount Back, preFix = %s, auto_p%d \n", preFix.c_str(), curCount);
}
void processMPtr(const string& preFix){
printf("processMPtr(const string& preFix) mPtr = %x \n", mPtr);
if(mPtr != nullptr){
(*mPtr).curRefCount --;
printf("processMPtr(const string& preFix) (*mPtr).curRefCount = %d \n", (*mPtr).curRefCount);
if((*mPtr).curRefCount == 0){ //不用 < 1, 防止多線程出毛病
printf("%s auto_p%d.curRefCount <= 1, delete auto_p%d mPtr= %x \n", preFix.c_str(), curCount, curCount, mPtr);
delete mPtr;
mPtr = nullptr;
}
}
}
};
class Test : public BaseType{
public:
//Test* test; //為了讓 AutoPtr 來(lái)管理指針, 就不要使用 Test* 了
AutoPtr<Test>* mTest; //測(cè)試循環(huán)引用
//類(lèi)的非靜態(tài)成員變量, 在類(lèi)的實(shí)例化過(guò)程中(構(gòu)造對(duì)象)才在棧區(qū)或者堆區(qū)為其分配內(nèi)存
//因?yàn)?AutoPtr<Test> 中存儲(chǔ)的 Test* 指向的對(duì)象必定是在堆區(qū)中創(chuàng)建的, 所以 Test 類(lèi)中的 mTestRef 即使不使用指針也不會(huì)在棧區(qū)里創(chuàng)建
//頂多調(diào)用一次 AutoPtr 的拷貝構(gòu)造函數(shù)
//AutoPtr<Test> mTestRef;
string content;
Test() {
cout << "Test Constructor" << endl;
}
Test(string content) : content(content) {
cout << "Test Constructor, content = " << content << endl;
}
Test(Test &t) {
cout << "Test CopyConstructor" << endl;
}
~Test() {
cout << "Test DeConstructor, this addr = " << this << endl;
}
};
//測(cè)試一次賦值
void test_auto_ptr1_simple_assign(){
AutoPtr<Test> auto_p1(new Test("Test1"));
AutoPtr<Test> auto_p2(new Test("Test2"));
auto_p1 = auto_p2;
cout << "auto_p1 content = " << auto_p1.value()->content << endl;
}
/**
Test Constructor
AutoPtr Constructor(), auto_p1
Test Constructor
AutoPtr Constructor(), auto_p2
AutoPtr operator=(AutoPtr& tp) auto_p1.curRefCount <= 1, delete auto_p1 mPtr=0xe65eb0
AutoPtr deConstructor, auto_p2 mTotalAutoPtrCount = 1
AutoPtr deConstructor, auto_p1 mTotalAutoPtrCount = 0
AutoPtr deConstructor auto_p1.curRefCount <= 1, delete auto_p1 mPtr=0xe65ed0
Process finished with exit code 0
*/
//測(cè)試多次賦值
void test_auto_ptr2_multi_assign(){
AutoPtr<Test> auto_p1(new Test());
AutoPtr<Test> auto_p2(new Test());
AutoPtr<Test> auto_p3(new Test());
auto_p1 = auto_p2;
auto_p3 = auto_p2;
auto_p1 = auto_p3;
}
/**
Test Constructor
AutoPtr Constructor(), auto_p1
Test Constructor
AutoPtr Constructor(), auto_p2
Test Constructor
AutoPtr Constructor(), auto_p3
AutoPtr operator=(AutoPtr& tp) auto_p1.curRefCount <= 1, delete auto_p1 mPtr=0x1015eb0
AutoPtr operator=(AutoPtr& tp) auto_p3.curRefCount <= 1, delete auto_p3 mPtr=0x1015ef0
AutoPtr deConstructor, auto_p3 mTotalAutoPtrCount = 2
AutoPtr deConstructor, auto_p2 mTotalAutoPtrCount = 1
AutoPtr deConstructor, auto_p1 mTotalAutoPtrCount = 0
AutoPtr deConstructor auto_p1.curRefCount <= 1, delete auto_p1 mPtr=0x1015ed0
Process finished with exit code 0
*/
//測(cè)試循環(huán)引用 (沒(méi)毛病)
void test_auto_ptr3_cycle_assign(){
AutoPtr<Test> auto_p1(new Test("Test1"));
AutoPtr<Test> auto_p2(new Test("Test2"));
auto_p1.value() -> mTest = &auto_p2;
auto_p2.value() -> mTest = &auto_p1;
cout << "auto_p1 content = " << auto_p1.value()->content << endl;
cout << "auto_p2 content = " << auto_p2.value()->content << endl;
}
/**
AutoPtr() Constructor auto_p1
AutoPtr(BaseType *_p) Constructor auto_p2
AutoPtr() Constructor auto_p3
AutoPtr(BaseType *_p) Constructor auto_p4
auto_p1 content = Test1
auto_p2 content = Test2
AutoPtr deConstructor, auto_p4 mTotalAutoPtrCount = 3
AutoPtr deConstructor auto_p4.curRefCount <= 1, delete auto_p4 mPtr=0x1025f00
AutoPtr deConstructor, auto_p2 mTotalAutoPtrCount = 2
AutoPtr deConstructor auto_p2.curRefCount <= 1, delete auto_p2 mPtr=0x1025eb0
Process finished with exit code 0
*/
//測(cè)試返回值, AutoPtr 對(duì)象從函數(shù)返回后, 函數(shù)的作用域消失, 函數(shù)內(nèi)部的 AutoPtr 對(duì)象析構(gòu)會(huì)影響返回的 AutoPtr 對(duì)象嗎? 不會(huì)
AutoPtr<Test> return_auto_ptr(){
AutoPtr<Test> auto_p1(new Test("Test1"));
AutoPtr<Test> auto_p2;
cout << "auto_p2 = auto_p1 Pre" << endl;
auto_p2 = auto_p1;
cout << "auto_p2 = auto_p1 End" << endl;
return auto_p2;
}
void test_auto_ptr4_return(){
AutoPtr<Test> autoPtr = return_auto_ptr(); //這里執(zhí)行拷貝構(gòu)造函數(shù)
cout << "test_auto_ptr4_return(), autoPtr content = " << autoPtr.value()->content << endl;
}
/**
AutoPtr() Constructor auto_p1
AutoPtr(BaseType *_p) Constructor auto_p2
AutoPtr() Constructor auto_p3
auto_p2 = auto_p1 Pre
auto_p2 = auto_p1 End
AutoPtr deConstructor, auto_p2 mTotalAutoPtrCount = 2
test_auto_ptr4_return(), autoPtr content = Test1
AutoPtr deConstructor, auto_p3 mTotalAutoPtrCount = 1
AutoPtr deConstructor auto_p3.curRefCount <= 1, delete auto_p3 mPtr=0xfd5eb0
Process finished with exit code 0
*/
//測(cè)試初始化 (好使)
void test_auto_ptr_init(){
AutoPtr<Test> tempPtr = AutoPtr<Test>(new Test("test_auto_ptr_init"));
cout << "tempPtr2 = tempPtr Pre, tempPtr value refCount = " << tempPtr.value()->curRefCount << endl;
AutoPtr<Test> tempPtr2 = tempPtr;
//這里不會(huì)執(zhí)行 operator = 函數(shù), 但是會(huì)執(zhí)行拷貝構(gòu)造函數(shù)
cout << "tempPtr2 = tempPtr Back, tempPtr value refCount = " << tempPtr.value()->curRefCount << endl;
}
/**
Test Constructor, content = test_auto_ptr_init
processCurCount Pre, preFix = AutoPtr(BaseType *_p) Constructor, mTotalAutoPtrCount = 0
processCurCount Back, preFix = AutoPtr(BaseType *_p) Constructor, auto_p1
tempPtr2 = tempPtr Pre, tempPtr value refCount = 1
*************** Auto CopyConstructor *******************
processCurCount Pre, preFix = AutoPtr CopyConstructor, mTotalAutoPtrCount = 1
processCurCount Back, preFix = AutoPtr CopyConstructor, auto_p2
tempPtr2 = tempPtr Back, tempPtr value refCount = 2
-------------- ~AutoPtr() Pre ----------
AutoPtr deConstructor, auto_p2 mTotalAutoPtrCount = 1
processMPtr(const string& preFix) mPtr = 6a5ed0
processMPtr(const string& preFix) (*mPtr).curRefCount = 1
-------------- ~AutoPtr() Back ----------
-------------- ~AutoPtr() Pre ----------
AutoPtr deConstructor, auto_p1 mTotalAutoPtrCount = 0
processMPtr(const string& preFix) mPtr = 6a5ed0
processMPtr(const string& preFix) (*mPtr).curRefCount = 0
AutoPtr deConstructor auto_p1.curRefCount <= 1, delete auto_p1 mPtr= 6a5ed0
-------------- ~AutoPtr() Back ----------
請(qǐng)按任意鍵繼續(xù). . .
Process finished with exit code 0
*/
//測(cè)試多線程
AutoPtr<Test> globalPtr = AutoPtr<Test>(new Test("thread AutoPtr"));
mutex mut;
void thread_func(int num) {
//加鎖解決當(dāng)前同步寫(xiě)的問(wèn)題
mut.lock();
std::cout << "------ thread_func Pre ------" << endl;
std::cout << "thread_func num = " << num << endl; //cout 不是線程安全的
AutoPtr<Test> innerPtr = globalPtr; //內(nèi)部有風(fēng)險(xiǎn),取數(shù)據(jù)無(wú)所謂,如果是寫(xiě)數(shù)據(jù)
std::cout << "globalPtr content = " << globalPtr.value() -> content << std::endl;
std::cout << "------ thread_func Back ------" << endl;
mut.unlock();
}
//測(cè)試多線程 (好使)
void test_auto_ptr5_multi_thread(){
std::thread t1(thread_func, 1);
std::thread t2(thread_func, 2);
std::thread t3(thread_func, 3);
std::thread t4(thread_func, 4);
std::thread t5(thread_func, 5);
t1.join();
t2.join(); //如果只有 t1.join(), 那么 exit code 就是 3 而不是 0
t3.join();
t4.join();
t5.join();
}
/**
Test Constructor, content = thread AutoPtr
processCurCount Pre, preFix = AutoPtr(BaseType *_p) Constructor, mTotalAutoPtrCount = 0
processCurCount Back, preFix = AutoPtr(BaseType *_p) Constructor, auto_p1
------ thread_func Pre ------
thread_func num = 1
*************** Auto CopyConstructor *******************
processCurCount Pre, preFix = AutoPtr CopyConstructor, mTotalAutoPtrCount = 1
processCurCount Back, preFix = AutoPtr CopyConstructor, auto_p2
globalPtr content = thread AutoPtr
------ thread_func Back ------
-------------- ~AutoPtr() Pre ----------
AutoPtr deConstructor, auto_p2 mTotalAutoPtrCount = 1
processMPtr(const string& preFix) mPtr = fb5eb0
processMPtr(const string& preFix) (*mPtr).curRefCount = 1
-------------- ~AutoPtr() Back ----------
------ thread_func Pre ------
thread_func num = 2
*************** Auto CopyConstructor *******************
processCurCount Pre, preFix = AutoPtr CopyConstructor, mTotalAutoPtrCount = 1
processCurCount Back, preFix = AutoPtr CopyConstructor, auto_p2
globalPtr content = thread AutoPtr
------ thread_func Back ------
-------------- ~AutoPtr() Pre ----------
AutoPtr deConstructor, auto_p2 mTotalAutoPtrCount = 1------ thread_func Pre ------
thread_func num = 3
processMPtr(const string& preFix) mPtr = fb5eb0
processMPtr(const string& preFix) (*mPtr).curRefCount = 1
-------------- ~AutoPtr() Back ----------
*************** Auto CopyConstructor *******************
processCurCount Pre, preFix = AutoPtr CopyConstructor, mTotalAutoPtrCount = 1
processCurCount Back, preFix = AutoPtr CopyConstructor, auto_p2
globalPtr content = thread AutoPtr
------ thread_func Back ------
-------------- ~AutoPtr() Pre ----------
AutoPtr deConstructor, auto_p2 mTotalAutoPtrCount = 1
processMPtr(const string& preFix) mPtr = fb5eb0
processMPtr(const string& preFix) (*mPtr).curRefCount = 1
-------------- ~AutoPtr() Back ----------
請(qǐng)按任意鍵繼續(xù). . .
-------------- ~AutoPtr() Pre ----------
AutoPtr deConstructor, auto_p1 mTotalAutoPtrCount = 0
processMPtr(const string& preFix) mPtr = fb5eb0
processMPtr(const string& preFix) (*mPtr).curRefCount = 0
AutoPtr deConstructor auto_p1.curRefCount <= 1, delete auto_p1 mPtr= fb5eb0
-------------- ~AutoPtr() Back ----------
Process finished with exit code 0
*/
int main() {
// test_auto_ptr1_simple_assign();
// test_auto_ptr2_multi_assign();
// test_auto_ptr3_cycle_assign();
// test_auto_ptr4_return();
test_auto_ptr5_multi_thread();
// test_auto_ptr_init();
system("pause");
return 0;
}