看程序:
#define_CRT_SECURE_NO_WARNINGS
#include
usingnamespacestd;
className
{
public:
//构造函数
Name(constchar*myp)
{
len=strlen(myp);//字符串的长度,不含'0'
p=(char*)malloc(len+1);//申请内存,要包含0
strcpy (p,myp);//字符串放到类中
}
//析构函数
~Name()
{
if(p!=NULL)
{
free(p);
p=NULL;
len=0;
}
}
protected:
private:
char*p;
intlen;
};
voidobjplay()
{
Name obj1("abcdefg");
Name obj2=obj1;//调用obj2的拷贝构造函数
//没写拷贝构造函数,使用C++编译器默认的拷贝构造函数
//C++编译器提供的拷贝构造函数是一个浅拷贝
//就是指针变量赋值了,但是指针变量所指向的内存空间没有被拷贝过去
}
intmain()
{
objplay();
system("pause");
return0;
}
我们运行上面的程序,发现运行出错:
我们分析一下:Name obj1("abcdefg");这个语句我们定义一个类的对象,此时会调用构造函数,在构造函数中申请一块内存,用于存放字符串。
接下来Name obj2=obj1;定义一个对象obj2,因为没有拷贝构造函数,因此会调用默认的拷贝构造函数,这个构造函数是一个浅拷贝。就是指针变量赋值了,指针变量指向的内存空间没有拷贝过去。
解释一下浅拷贝:
简单的说,在有指针的情况下,浅拷贝只是增加了一个指针指向已经存在的内存。(而深拷贝是增加一个指针并且申请一个新的内存,使这个增加的指针指向这个新的内存,采用深拷贝的情况下,释放内存的时候就不会出现浅拷贝时重复释放同一内存的错误。)
我们来分析一下为什么会运行出错!
先来看对象obj1,对象有两个属性,指针p和存放字符串长度的len,执行语句Name obj1("abcdefg");时会调用构造函数,在构造函数中将字符串的长度7赋给len,因此len变量的内存中就是7,然后申请内存,指针p指向这块内存,然后将字符串投放到申请的内存中。
然后执行Name obj2=obj1;会调用默认的拷贝构造函数,但这个默认的拷贝构造函数是一个浅拷贝,就是说,把对象obj1的两个属性,拷贝一份然后给obj2,是把指针变量的值拷贝了,但是没有把指针变量指向的内存内容也拷贝一份,也就是两个指针指向同一块内存。
然后函数执行完后我们会调用析构函数,先构造的后析构,因此先析构obj2对象,会调用析构函数,会把刚刚申请的内存空间给析构释放,然后p变成NULL,len变成0。
但是obj2的属性跟obj1的属性是没有关系的,obj2析构了,但是obj1还在,obj1中的指针p还指向一个已经释放的内存,也就成了野指针,接下来析构obj1对象会调用obj1的析构函数,又会执行一次析构,因为之前申请的内存空间已经析构了,所以再析构,析构两次同一块内存空间,就会出错。
下一个笔记,也就是笔记五十,说一下用深拷贝解决上面这个问题。
领取专属 10元无门槛券
私享最新 技术干货