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.