类的指针成员管理

之前纠结的那个NoName中的指针成员问题,13.5章有集中讨论了

类的指针成员管理:danglingPtr.cpp删除ip后的一些操作和结果:    delete ip;std::cout << "After delete: *" << ip << " is " << *ip << std::endl;//证明delete还是有效的,把对象清零了,但是指针指向原位置。ptr.set_ptr_val(220);//虽然强行给原int对象赋值是个灾难std::cout << ptr.get_ptr_val() << std::endl;//但是一个普通的int,disaster显不出来,还能正常用应该用个string之类的13.21题,要写一个析构函数,来删除指针成员。

书中老是说不明白这个问题,前边的NoName应该就是表达错误

如果析构中真的有delete *ptr;这种删除对象的析构的话, 

    int i = 42;    HasPtr p1(&i, 42);

直接就内存错误了,至少退出main会析构一次,就错了

关于智能指针--其实就是想办法加一个计数功能,保证所有对象撤销的时候才delete 指针

利用一个“私有类”来完成计数功能

小技巧,U_ptr 的所有成员全是私有,指定友元,使U_ptr完全成为HasPtr的私有类。

未完成--还缺赋值操作符等。。。。

U_Ptr.cpp

//析构函数,删除指针成员,会发生什么?
//跟书上学一句话函数体不是好习惯,多了语句一定要转换成正常模式来看
//重点?智能指针只是保障了同一个对象内不能delete两次指针,但是不用copy会出现多个U_Ptr对象,这样每个U_Ptr对象 delete ip;互相都不冲突?为什么?
//delete掉的不该是指向的对象么?事实证明也是,析构之后,原p指向的42被清零
#include"head.h"
class U_Ptr{
	friend class HasPtr;
	int *ip;
	size_t use;
	U_Ptr(int *p): ip(p), use(1) {}
	~U_Ptr(){
		std::cout << "end:destructor" << std::endl;
		delete ip;//问题还在这个delete 指针上。
	}
};
class HasPtr{
public:
	//copy of the values we're given
	HasPtr(int *p, int i): ptr(new U_Ptr(p)), val(i){std::cout << "test: *ptr->ip is " << *ptr->ip << std::endl;}//constructor
	HasPtr(const HasPtr &orig): ptr(orig.ptr), val(orig.val){ ++ptr->use;}//copy members and increment the use count
	~HasPtr(){
		//为什么程序结束,析构,第一个无hello,第二个有hello,因为if语句导致只有最后一次(由此发现了导致程序错误的if语句失误)
		if(--ptr->use == 0){
			std::cout << "hello" << std::endl;//终于找到毛病了,乱添加测试语句,导致if判断失效,加花括号解决,
			delete ptr;//错误原因,判断失效,导致删除两次U_Ptr,事实只产生一个U_Ptr,segmental fault	
		}
	}
	
private:
	U_Ptr *ptr;
	int val;
};

int main(){
	
	int *p = new int( 42);//问题也不是在这
	{	
		HasPtr ptr1(p, 20);
		std::cout << std::endl;
		HasPtr ptr2(ptr1);
		HasPtr ptr3(ptr2);
		HasPtr ptr4(p, 77);//需要另一个U_Ptr,因此delete ptr两次,两个对象里分别delete一次,但是指向相同却没冲突?想delete多少次都成?
		std::cout << "---------------" << std::endl;
		int *p2 = p;
		int *p3 = p;
	//	delete p2;//同样都是指针,在类外的delete个p2就不行,在类内delete好几次ptr就可以,为什么这么特殊~?????!!!
	
	}//delete p的错误是,HasPtr超出scope(main)才析构,所以是先delete p;这样导致类内指针悬垂,避免方法是用个函数块
	std::cout << p << " : " << *p << std::endl;
	//delete p;
	
}


最后是值型类,


class HasPtr{
public:
	HasPtr(int *p, int i): ptr(new int(*p)), val(i){}
	
	HasPtr(const HasPtr &orig): ptr(new int(*orig.ptr)), val(orig.val){}
	~HasPtr(){delete ptr;}
	HasPtr&
	operator=(const HasPtr &rhs){
		*ptr = *rhs.ptr;//不用new个int,只需要把赋值,相当于正常int对象的赋值操作
		val = rhs.val;
		return *this;
	}
	//其他操作
	int get_ptr_val() const{return *ptr;}
	int get_int() const{return val;}
	
	void set_ptr(int *p){ptr = p;}
	void set_int(int i){val = i;}
	//return or change the value pointed to,so ok for const objects
	int *get_ptr() const{return ptr;}
	void set_ptr_val(int p) const{*ptr = p;}
private:
	int *ptr;
	int val;
	
	
};


Q:每次到底是叫删除对象还是删除指针,如何删除指针?delete是删对象啊,合成析构函数做的:有内置类型的自动撤销,有类类型的析构调用,可是内置类型的指针算什么?书中没说明如果自己写这个函数,要怎么再去调用string和其他类类型的析构函数   

A:是删除对象,没错,指针指向的对象。虽说每个类成员是int *ptr;指针而已,看似不储存整型对象,实际容易忘了这局初始化语句,是new一个int对象,让类对象的整型指针指向这个新建的整型对象,析构delete ptr也是删除每个类对象独有的int对象


智能指针的疑惑也在这,因为如果不用复制等手段,不同的HasPtr不一定通过一个U_Ptr对象来指向整型基础对象。所以delete ptr可以指第一个U_Ptr对象也可能是第二个U_Ptr对象。


因为并没有一个机制去检测我新建的HasPtr对象所用的*p是否重复,只能在复制和赋值时检测一下U_Ptr中的计数。

而初始化列表又是U_Ptr(int *p): ip(p), use(1){}这样直接复制的指针,也就是同一个int基础对象原则上讲会被不同的U_Ptr的ip指向,也就是可以被重复~U_Ptr(){delete ip;}啊,怎么解决?




后边13——28要二叉树的相关复制控制函数,先不弄了,要围绕二叉树支持的各种功能来做这个。

最后,小疑问,每次运行,每次初始化这个p,和后续用他来初始化的HasPtr对象的尾地址全是008,018,028,038,此规律何来


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值