管理指针成员

本文探讨了在C++中管理类内的指针成员时应注意的五个关键问题,并提出了三种解决方案:采用默认行为、使用智能指针以及实现值类型的深拷贝。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                                    管理指针成员

此话题是针对还有指针成员的类提起的,对于这样的类在管理时理应特别小心。

原因如下:

    注意指针成员的初始化问题

    注意指针成员的复制问题

    注意指针成员的释放问题

    注意指针成员的垂悬问题

    注意指针成员的赋值问题

首先我们来看一个含有指针成员的类:

class HasPtr

{

public:

HasPtr(int *p,int i):ptr(p),val(i){}

int *get_ptr()const //返回指针成员

{

    return ptr;

}

int get_int()const

{

    return val;

}

void set_ptr(int *p) //设置指针

{

    ptr = p;

}

void set_val(int i)

{

    val = i;

}

int get_ptr_val()const //返回指针成员的值

{

    return *ptr;

}

void set_ptr_val()const //设置指针成员的值

{

    *ptr = val;

}

private:

int *ptr;

int val;

};

我们对指针成员的管理有三种方法:

  指针成员采取常规的行为

这类管理方法产生的类含有指针的所有缺陷,他不设置特殊的复制控制。即程序员无需自己定义复制构造函数和赋值函数。

下面我们看一下这个方法的缺陷。

(1)int obj = 0;

  HasPtr ptr1(&obj,42);

  HasPtr ptr2(ptr1);

 此定义使对象 ptr1,ptr2中的指针成员均指向了obj.使两个对象失去了独立性。

(2)同时这样当我们修改其中一个对象的值时,同时也改变了另一个对象的值。

(3)对于这样的代码

int *ip = new int(42);

HasPtr ptr(ip,10);

delete ip;

ptr.set_ptr_val(0);

然而当我们删除保存int 对象的ip指针时,ptr就不指向有效的对象了。但是我们进行运行输出后,结果却是正确的,这是怎么回事呢?原本这里我也不理解,多亏一个朋友帮我解决了这个问题。谢谢他,这里之所以结果还是正确的,是因为我们申请空间属于堆内存,虽然我们这里释放了指针ip,但由于以后我们并没有申请空间,即原来ptr指向的那块内存并没有被占,所以他还保存着原来的值,所以我们这里修改成功了。若我们在输出前再来个动态分配,结果就不对了。。

   使用智能指针

所谓智能指针就是用来负责删除共享对象的指针,他可以判断当前是否还有指针指向该共享对象,若当前已是最后一个指向共享对象的指针,就删除共享对象。由此可知我们需要计数,统计指向共享对像的指针个数。我们每次定义一个类对象时,我们给他的指针成员复制的共享对象可能不同,故我们需要对每一个类对象进行计数。用来统计指向该共享对象的指针个数。这样在定义类的时候就可以在构造函数中将计数置1.在复制构造函数中将计数加1.在赋值函数中对右操作数的计数加1,对左操作数的计数减1.最后在调用析构函数的时候计数减1 然后判断计数是否为0,若为0,则删除共享对象。但是我们不能直接把计数放在对象中。否则会出现下面情况:

int obj;

HasPtr p1(&obj,42);

HasPtr p2(p1);

HasPtr p3(p1);

这段代码中我们让对象p2,p3指向了同一个共享对象,按我们上面的方法,我们分别在对象p2,p3中对指向该共享对象的指针做了计数,然而我们统计的仅仅是分别有p2,p3产生的指针数目。即若p2(p3)中的数目为0时,按我们的设计即可删除共享对象p1,不管此时p3(p2)中的数目是否为0.故这样就产生了垂悬指针的情况。况且我们无法对这样的情况对计数统一起来。故我们用另外一种方法,专设一个计数类。

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{

public:

HasPtr(int *p,int i):ptr(new U_Ptr(p)),val(i){}

HasPtr(const HasPtr,&orig):ptr(orig.ptr),val(orig.val){++ptr->use;}

HasPtr& operator=(const HasPtr&);

~HasPtr(){if (--ptr->use == 0)delete ptr;}

private:

 U_Ptr *ptr;

int val;

};

我们在定义一个对象时,对象指向的不在是共享对象,而是一个U_Ptr对象。U_Ptr对象可以由共享对象的指针进行初始化,而后我们在U_Ptr对象中进行计数,这样就预防了上述问题的发生。即,由某个U_Ptr对象初始化的指针数目为0时即可删除该U_Ptr对象。这样不会对共享对象产生任何影响。。

这里类里对于计数的设计和上面一样。

不过这样设计,仍存在一个问题,那就是改变一个对象,将会改变共享对象,所有共享该对象的对象值均会被改变。

  定义值类型

这种方法就是我们平时最常用的方法了,即我们为我们所定义的指针重新复制一个副本。这样他们之间就各自独立,互不影响了,同时就解决了以上所有的问题。

 

 

 

此总结 参考《C++ Primer

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值