C++易混点——深度解析指针悬挂和虚析构函数

1.指针悬挂及解决要点

1.1.何为指针悬挂:

指针悬挂值得是我们在程序的浅层拷贝过程中,因为默认的拷贝构造函数的局限性,导致的内存泄漏(至于泄露了那一部分内存,马上讲解),再长时间的积累下,每一次使用该函数的该复制 的特性,那么电脑中的内存就会丢失一块,长时间下来,导致电脑崩溃的事故发生,这一点对于C++这种没有Java垃圾内存回收机制的语言来说是开发中非常致命的一个大问题

1.2.泄露了那一部分内存:

当我们进行浅层拷贝的时候,电脑知识默认的将后者 的内存地址复制过去,使得两个指针对应的内存指向是相同的,那么之前一个内存不就变成了“野”内存,没有任何一个指针指向他,也就是说,我们永远无法找到那个内存区域,当然我们也就丢失了对他的控制了,这片内存就泄露了出去
代码举例:
class test
{
	public:
		//test(){
		//}
		//~test(){ 
		//}
		void set(int p)
		{
			key=&p;
		}
		void get()
		{
			printf("%d\n",*key);
		}
	private:
		int* key;
};

int main()
{
	test b,a;  
	b=a;     //b原本key指向的内存有可能会丢失
	return 0;
}
另一个错误,在我们调用异构函数的时候一旦我们采用这种浅层的拷贝,那么当一个析构完之后,另一个因为指向是相同的,但是该片内存已经释放过了,重复释放也会导致错误

1.3.如何避免:

我们目前避免这种情况的方法就是对等于号“=”进行运算符重载,我们重载的功能就是,在进行同等的复制的时候,我们先将原内存清理释放(可能会泄露的那块内存释放掉),然后再开批一个新的内存,对内存的额内容进行复制,从而防止上面的两个错误
示例代码如下:
#include"cstdio"
#include"cstdlib"
#include"cstring"
#include"iostream"

using namespace std;

class errornull{
};

class test
{
	public:
		test(){
			key=NULL;
		}
		~test(){ 
		free(key);
		}
		void set(int& p)   //注意必须加引用,否则我们指向的只是为了复制而开辟的随机的内存
		{
			key=&p;
		}
		void get()
		{
			printf("%d\n",*key);
		}
		test& operator=(test& k)
		{
			if(&k==this) return *this;    //特殊情况,如果是本身复制的话,直接返回就好
			else
			{
				try
				{
					if(k.key==NULL) throw errornull();
					if(key==NULL);
		    		else delete key;    //释放内存 
		    		key=new int;    //重新开辟 
		    		*key=*k.key;    //手动复制 
		    		return *this; 
				}
				catch(errornull e)
				{
					cout<<"正在尝试复制不存在的内容"<<endl;
				} 
			} 
		}
	private:
		int* key;
};

int main()
{
	test b,a;
	int s=3;
	a.set(s);
	a.get();
	b=a;
	b.get();
	return 0;
}


2.虚析构函数

2.1.虚析构函数的必要性:

我们一旦了解过多态的话都会知道(如果没有学过多态,请自行百度)
我们完全可以通过基类的指针来动态创建(或者直接指向一个已经存在过的)一个新的子类的对象,这里就是多态的一个优点
但是在析构函数这里(动态创建的情况下会出现),回出现一些麻烦的问题
首先我们都知道一个规则,就是继承的时候的构造的顺序:
构造:先基类后子类
析构:先子类后基类
代码里面好说一点:
#include"iostream"
#include"cstdio"
#include"cstdlib"

using namespace std;

class a
{
	public:
		a()
		{
			
		}
		~a()
		{
			
		}
	private:
		int key;
};

class b:public a
{
	public:
		b():a()
		{
			
		}
		~b()
		{
			
		}
	private:
		int oh;
};

int main()
{
	a* my;
	my=new b;  //在这里我们析构的话我们没有用 虚 来实现多态的控制的话,那么我们之后自动delete my的时候,调用的只是my的析构函数,我们
	//就相当于把子类b忘了,忘了析构子类,这时候必然会导致错误,所以我们致力的继承中析构函数都是用 虚 的,目的就是用指针析构的是真正的指向的子类,而不是子类中嵌套包含的基类的那一部分,而是子类全部
	//换句话说,我们的目的是调用子类的析构函数而不是基类的析构函数,这时候的virtual,虚析构函数的作用就和我们当时多态的一样了,自然就达到了我们所谓的删除了我们想删除的东西的目的 
	return 0;
}

3.参考文献

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值