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.