美文网首页
自定义完美的智能指针 AutoPtr

自定义完美的智能指针 AutoPtr

作者: 李云龙_ | 来源:发表于2023-03-26 21:19 被阅读0次

    STL 的 auto_ptr 已经弃用, 为了解决手动释放指针内存的问题, 自定义一个好使的 AutoPtr 包装类, 不足的一点是所有被包装的类必须继承自 BaseType, 因为 BaseType 中有当前被包装类的对象的引用计数。

    每有一个 AutoPtr 对象的 mPtr 指针指向被包装类的对象, 那么该被包装类的对象的引用计数就 + 1;每有一个 AutoPtr 对象析构, 那么 AutoPtr 对象的 mPtr 指针指向被包装类的对象的引用计数就 -1, 当执行AutoPtr 对象的析构函数发现 mPtr 指针指向的被包装类的对象的引用计数变为 0 时, 就 delete 掉 mPtr 指针, 释放被包装类的对象的内存, 从而解决了手动 delete 释放内存的问题。

    代码如下 :

    #include <iostream>
    #include <vector>
    #include <thread>
    #include <mutex>
    
    using namespace std;
    
    //自己编写智能指针代理类 AutoPtr
    //mTotalAutoPtrCount 目前只能针对一种 Tp 类型
    static int mTotalAutoPtrCount = 0; //使用 mCurCount 判断当前是 auto_p1 还是 auto_p2
    
    template<typename Type>
    class AutoPtr;
    
    class BaseType{
    public:
        //AutoPtr * autoPtr;
        int curRefCount = 0; //当前对象的 AutoPtr 引用计数
    
        BaseType(){
    
        }
    };
    
    //如何让 Type 继承自 BaseType ?
    
    template<typename Type>
    class AutoPtr {
    private:
        //外部的数据
        BaseType* mPtr = nullptr;
        int curCount = 0;
    
    public:
        explicit AutoPtr() throw() {
            processCurCount("AutoPtr() Constructor");
        }
    
        explicit AutoPtr(BaseType *_p) throw(): mPtr(_p) {
            ((*_p).curRefCount) ++; //AutoPtr 对象引用 BaseType 对象
            processCurCount("AutoPtr(BaseType *_p) Constructor");
        }
    
        //拷贝构造函数        //注意 : 这么写不好使, 必须是 const AutoPtr<Type>& autoPtr 拷贝构造函数才会执行 !
    //    AutoPtr(const AutoPtr<BaseType>& autoPtr): mPtr(autoPtr.mPtr){
    //        cout << "*************** Auto CopyConstructor *******************" << endl;
    //        (autoPtr.value() -> curRefCount) ++;
    //        processCurCount("AutoPtr CopyConstructor");
    //    }
    
        //拷贝构造函数
        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;
        }
    
        //如果要进行 * 号操作, 那么直接返回里面的 _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 来管理指针, 就不要使用 Test* 了
        AutoPtr<Test>* mTest;   //测试循环引用
    
        //类的非静态成员变量, 在类的实例化过程中(构造对象)才在栈区或者堆区为其分配内存
        //因为 AutoPtr<Test> 中存储的 Test* 指向的对象必定是在堆区中创建的, 所以 Test 类中的 mTestRef 即使不使用指针也不会在栈区里创建
        //顶多调用一次 AutoPtr 的拷贝构造函数
        //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;
        }
    };
    
    //测试一次赋值
    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
     */
    
    //测试多次赋值
    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
     */
    
    //测试循环引用 (没毛病)
    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
     */
    
    //测试返回值, AutoPtr 对象从函数返回后, 函数的作用域消失, 函数内部的 AutoPtr 对象析构会影响返回的 AutoPtr 对象吗? 不会
    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(); //这里执行拷贝构造函数
        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
    */
    
    
    //测试初始化 (好使)
    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;
        //这里不会执行 operator = 函数, 但是会执行拷贝构造函数
        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 ----------
        请按任意键继续. . .
    
        Process finished with exit code 0
     */
    
    //测试多线程
    AutoPtr<Test> globalPtr = AutoPtr<Test>(new Test("thread AutoPtr"));
    mutex mut;
    
    void thread_func(int num) {
        //加锁解决当前同步写的问题
        mut.lock();
    
        std::cout << "------ thread_func Pre ------" << endl;
    
        std::cout << "thread_func num = " << num << endl; //cout 不是线程安全的
    
        AutoPtr<Test> innerPtr = globalPtr; //内部有风险,取数据无所谓,如果是写数据
    
        std::cout << "globalPtr content = " << globalPtr.value() -> content << std::endl;
    
        std::cout << "------ thread_func Back ------" << endl;
    
        mut.unlock();
    }
    
    //测试多线程 (好使)
    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 ----------
        请按任意键继续. . .
    
        -------------- ~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;
    }
    

    相关文章

      网友评论

          本文标题:自定义完美的智能指针 AutoPtr

          本文链接:https://www.haomeiwen.com/subject/jyrardtx.html