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;
}