当类中的有指针成员时,对象之间的复制时,会造成对象的指针成员指向同一个基础对象。当两个指针指向同一对象时,可能使用任一指针改变基础对象。类似地,很可能一个指针删除了一个对象,另一指针的用户还认为基础对象仍然存在,此时会造成悬垂指针,即指针指向不存在的对象。
class HasPtr{
private:
int val;
int* ptr;
public:
HasPtr(int i,int* p):val(i),ptr(p){}
HasPtr(const HasPtr& orig):val(orig.val),ptr(orig.ptr){}
HasPtr& operator=(const HasPtr&);
~HasPtr(){}
void get_ptr(){
cout<<*ptr<<endl;
}
};
int main(void){
int *p=new int(20);
HasPtr obj1(10,p);
delete p;
obj1.get_ptr();
return 0;
}
为此C++引入智能指针的概念,即定义一个智能指针类,类中主要包含两个成员:指针和计数变量。使用智能指针类中的指针成员指向基础对象,使用计数变量来表示有多少个对象共享同一指针。
智能指针类:
class U_Ptr{
friend class HasPtr;
int *ip;
size_t use;
U_Ptr(int *p):ip(p),use(1){}
~U_Ptr(){delete ip;}
};
class HasPtr{
private:
int val;
U_Ptr *ptr;
public:
HasPtr(int *p,int i):ptr(new U_Ptr(p)),val(i){
cout<<ptr->use<<endl;
}
HasPtr(const HasPtr& orig):ptr(orig.ptr),val(orig.val){
++ptr->use;
cout<<ptr->use<<endl;
}
HasPtr& operator=(const HasPtr&);
~HasPtr(){
if(--ptr->use==0)
delete ptr;
cout<<"destructor"<<" "<<ptr->use<<endl;
}
void Outuse(){
cout<<ptr->use<<endl;
}
};
int main(void){
int *p=new int(20);
HasPtr obj1(p,10);
HasPtr obj2(obj1);
return 0;
}
结果:
由此看出,每当复制构造一个新对象时,计数器+1;每当删除一个对象时,当计数器。
最核心的问题:析构函数到底做了什么,可以导致删除对象obj2的时候不影响U_Ptr的指针ip呢。看了书和博客,一直没理解这个问题。
问题解决:使用默认析构函数删除对象obj2的时候,会删除obj2里的指针成员obj2.ptr,这里的删除是将指针所在的内存空间释放,而不是将指针所指向的内存空间释放(delete ptr),所以不会对基础对象产生影响。