参考文章 :
当一个类有指针成员的时候,这样的类叫非平凡的类。
这个指针成员一般都是在管理着堆上的内存(比如,堆变量的地址)。
下面的代码展示了有指针成员的对象管理动态内存的过程:
- #include
- using namespace std;
-
- class Student
- {
- public:
- int* m_age;//指针成员:管理动态内存
- //构造函数中申请堆内存
- Student() :m_age(new int(18)) //3 执行构造函数
- {
- }
- ~Student()//5 析构函数释放堆内存
- {
- delete m_age;
- }
- };
-
- int main()
- {
- //1 main函数开始执行
- Student stu;//2 在栈上创建新对象stu(分配内存),接下来调用构造函数
-
- return 0;
- }//4 stu对象超出作用域,接下来调用析构函数
像上面的m_age这种成员变量,在对象之间的赋值(浅拷贝)的时候,就会导致两个对象的指针成员都指向了同一个地址。
- Student stu1;
- Student stu2;//(1)
- stu2 = stu1;//(2)出问题了!!!两个指针成员同时指向了一个堆变量
因为一个对象要析构的时候会释放这个地址的内存。另一个对象释放的时候也要释放这个内存。
这会导致两次释放同一个内存,第一次释放内存的时候内存就归还给系统了。
当你第二次再释放这个内存的时候,你在释放不再归你管的内存,操作系统会把你的程序杀掉。运行的时候你的程序就会闪退。
为了避免上面的问题,那解决的办法就是(深拷贝)。
一个对象在被赋值的时候,另开炉灶,在堆上再重新开辟一个属于自己的内存,把数值拷贝进去。
这样两个对象各自管理属于自己的内存,就不会有问题。这就是深拷贝。
拷贝对象主要发生在两个地方:拷贝构造函数,赋值。
非平凡类的拷贝构造函数
拷贝构造函数是构造函数的一个,这个函数的参数是该类型的另一个对象。
- class Student
- {
- public:
- int* m_age;//指针成员:管理动态内存
- //构造函数中申请堆内存
- Student() :m_age(new int(18))
- {
- }
- //copy constructor 拷贝构造函数(函数名为类名,参数为同类型的另一个对象
- Student(const Student& stuFrom);
- ~Student()
- {
- delete m_age;//析构函数释放堆内存
- }
- };
- //拷贝构造函数,新开辟一个堆变量,用m_age管理,数值设置为from的m_age管理的对变量的数值
- Student::Student(const Student& from):m_age(new int(*from.m_age))
- {
- }
拷贝构造函数执行的时机:拷贝构造函数(浅拷贝)
(1)用一个对象构造另一个对象
- Student stu1;//(1)
- Student stu2(stu1);//(2)
(2)函数传值
- void test_function(Student s)//s的创建会调用拷贝构造函数
(3)函数返回值类型
- Student test_function(void)// return语句执行的时候会调用拷贝构造函数
赋值操作符和拷贝操作符类似,属于深拷贝。
- Student stu1;
- *stu1.m_age = 18;
- Student stu2;
- *stu2.m_age = 19;
- stu2 = stu1;//赋值操作符
-
- class Student{
- Student& operator=(const Student& stuFrom);
- };
- // stu2
- Student& Student::operator=(const Student& stuFrom){
- if(this == &stuFrom)//自己赋值给自己,直接返回自己
- {
- return *this;
- }
- *m_age = *stuFrom.m_age;//深拷贝,将存储的数据拷贝,而不是直接地址拷贝
- return *this;
- }
复制控制,专门指上文提到的深拷贝。如需要专门重写拷贝构造函数,赋值操作符来加以管理。
1 C++提供三个默认实现:默认构造函数 default constructor;拷贝构造函数 copy constructor; 析构函数 destructor
2 非平凡的类需要自己重新定义拷贝控制函数,赋值操作符 operator=
3 复制控制 = 默认构造函数 default constructor + 拷贝构造函数 copy constructor + 析构函数 destructor + 赋值操作符 operator=