zoukankan      html  css  js  c++  java
  • C++自学笔记_定义智能指针类_《C++ Primer》

    包含指针的类要特别注意复制控制,原因是复制指针只复制指针中的地址,而不会复制指针所指向的对象。

    C++类采用以下3种方法之一管理指针成员:

    (1) 指针成员采取常规指针型行为。这样的类具有指针所有的缺陷但是无需特殊的复制控制。

    (2) 类可以是实现“智能指针”行为。指针所指向的对象是共享的,但类能够防止悬垂指针。

    (3) 类采取值型行为。指针所指向的对象是唯一的,由每个类对象单独管理。

    这里总结第(2)种方法——采用定义智能指针类

    智能指针类的思想在于:

    第(1)种方法中,所有的对象中的指针都直接指向同一个基础对象(比如一个int型对象),这样导致的结果是其中任何一个对象进行析构都会把这个

    基础对象给delete,此时别的对象中的指针成员已经成为了一个悬垂指针了。

    而第(2)种方法,所有的对象中依旧有指针成员,但是此时新增一个计数类,每个计数类对象分别指向不同的基础对象,但这一切对使用者来说是

    透明的。当我定义的类对象中的指针要指向一个基础对象时,我们不把类对象的指针直接指向这个基础对象,而是把这个对象的指针指向定义的

    计数类对象,计数类对象指向我们原本要指向的基础类对象,计数类对象包含两个属性:一个指向基础对象的指针、一个计数器。

    example:
    #include <iostream>
    
    using namespace std;
    
    class HasPtr;    //HasPtr类的声明
    
    /*U_ptr是一个计数类,用来统计指向某个int对象的HasPtr对象的个数*/
    class U_ptr{
        friend class HasPtr;
        U_ptr(int *p):ip(p),use(1){ }   //构造函数
        ~U_ptr(){ delete ip; }
        int *ip;            //不直接通过HasPtr对象指向一个int对象,而是通过U_ptr对象来管理
        size_t use;         //记录有多少个HasPtr对象指向某个int对象
    };
    
    class HasPtr{
    public:
        HasPtr(int *p,int i):             //构造函数,参数依旧是int*类型,通过调用U_ptr的构造函数来构造
            ptr(new U_ptr(p)),val(i){ }
        HasPtr(const HasPtr &orig):                      //复制构造函数,此时ptr和orig.ptr指向
            ptr(orig.ptr),val(orig.val){ ++ptr->use; }   //同一个U_ptr对象,并把这个U_ptr对象内的use加1
        HasPtr& operator=(const HasPtr&);
        ~HasPtr() { if(--ptr->use==0) delete ptr; }      //析构函数,只有当析构了以后会
                                                         //导致U_ptr对象内的use减小到0才delete
        int* get_Ptr()const { return ptr->ip; }
        int get_int()const { return val; }
        void set_ptr(int *p){ ptr->ip=p; }
        void set_int(int i){ val=i; }
        int get_ptr_val()const { return *ptr->ip; }
        void set_ptr_val(int i){ *ptr->ip=i; }
    private:
        U_ptr *ptr;        //现在HasPtr对象不再直接指向int对象,而是指向计数类对象
        int val;
    };
    
    HasPtr& HasPtr::operator=(const HasPtr &obj){
        ++obj.ptr->use;
        cout<<"obj.ptr->use="<<obj.ptr->use<<endl;
        if(--ptr->use==0){
            cout<<"ptr->use="<<ptr->use<<endl;
            delete ptr;
        }
        ptr=obj.ptr;
        val=obj.val;
        return *this;
    }
    
    int main()
    {
        int num1=10;
        int num2=11;
        HasPtr obj1(&num1,20);
        HasPtr obj2(&num2,22);
        cout<<"obj1:"<<endl;
        cout<<"obj1.get_int(): "<<obj1.get_int()<<endl;
        cout<<"obj1.get_ptr_val(): "<<obj1.get_ptr_val()<<endl<<endl;
        cout<<"obj2:"<<endl;
        cout<<"obj2.get_int(): "<<obj2.get_int()<<endl;
        cout<<"obj2.get_ptr_val(): "<<obj2.get_ptr_val()<<endl<<endl;
        obj1=obj2;
        cout<<endl<<"obj1:"<<endl;
        cout<<"obj1.get_int(): "<<obj1.get_int()<<endl;
        cout<<"obj1.get_ptr_val(): "<<obj1.get_ptr_val()<<endl<<endl;
        return 0;
    }

    编译运行后的结果:
    obj1:
    obj1.get_int(): 20
    obj1.get_ptr_val(): 10
    
    obj2:
    obj2.get_int(): 22
    obj2.get_ptr_val(): 11
    
    obj.ptr->use=2
    ptr->use=0
    
    obj1:
    obj1.get_int(): 22
    obj1.get_ptr_val(): 11
    
    
    Process returned 0 (0x0)   execution time : 2.007 s
    Press any key to continue.
     
     
  • 相关阅读:
    博客园项目
    social-auth-app-django模块
    win10安装软件被阻止后
    expdp和impdp的用法
    EXPDP
    oracle常用的数据迁移方法
    使用spool导出数据
    无法创建spool文件
    sqlldr导入数据
    cmd 登录oracle
  • 原文地址:https://www.cnblogs.com/Murcielago/p/4205229.html
Copyright © 2011-2022 走看看