如果类内部涉及到动态内存分配,通常情况下需要实施深拷贝
如果要共享内存要另当别论,如果要共享内存,最后一个对象销毁的时候才调用析构函数,只析构一次。
系统提供的默认拷贝函数实施的是浅拷贝
深拷贝,是自己定义的拷贝构造函数决定如何复制。
浅拷贝就是位拷贝,如果类有个指针成员,只复制指针,并不复制指针所指向的内存
如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。
如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。
下面用代码示例进行说明:
String.h
- //String.h
- # ifndef _STRING_H_
- # define _STRING_H_
- class String
- {
- public:
- String(char* str = " ");
- ~String();
- String(const String& other);
- String& operator = (const String& other);
- void Display();
- private:
- char* AllocAndCopy(char* str);
- char* str_;
- //如果类内部涉及到动态内存分配
- //通常情况下需要实施深拷贝
- //如果要共享内存要另当别论
- //如果要共享内存,最后一个对象销毁的时候才
- //调用析构函数,只析构一次
- };
- # endif //
String.cpp
- //String.cpp
- # include "String.h"
- //# include <string.h>
- # include <cstring>
- # include <iostream>
- using namespace std;
- //实施浅拷贝,系统默认的构造函数
- String::String(char* str)
- {
- /*int len = strlen(str) + 1;
- str_ = new char[len];
- memset(str_,0,len);
- strcpy(str_, str);*/
- //以上由AllocAndCopy(str_);代替
- str_ = AllocAndCopy(str);//此为浅拷贝
- }
- //实施深拷贝
- String::String(const String& other)
- {
- /*int len = strlen(other.str_)+1;
- str_ = new char[len];
- memset(str_,0,len);
- strcpy(str_, other.str_);*/
- //以上由AllocAndCopy(char * str_);代替
- str_ = AllocAndCopy(other.str_); //此为深拷贝
- }
- char* String::AllocAndCopy(char* str)
- {
- int len = strlen(str) + 1;
- char * tmp = new char[len];
- memset(tmp, 0,len);
- strcpy(tmp, str);
- return tmp;
- }
- String& String::operator=(const String &other)
- {
- if(this == &other)
- {
- return *this;
- }
- //首先要销毁空间,因为它原来就存在了
- delete[] str_;
- str_ = AllocAndCopy(other.str_);
- return *this;
- }
- String::~String()
- {
- delete[] str_;
- }
- void String::Display()
- {
- cout << "Str = " << str_ << endl;
- }
main.cpp
- # include "String.h"
- int main(void)
- {
- String s1("AAA");
- //String s2("BBB");
- s1.Display();
- String s2 = s1;//调用默认的拷贝构造函数,如果有深拷贝调用深拷贝,如果没有深拷贝,则在运行时出错
- //系统提供的默认拷贝函数实施的是浅拷贝
- //等价s2.str_ = s1.str_ ; 指向同一块内存,没有分配自己的内存
- //当两个对象生成周期结束的时候,被释放了两个同一个内存空间
- //提供一个自己的拷贝函数
- s2.Display();
- String s3;
- s3.Display();
- //s3 = s2; error 本质原因调用了等号运算符,
- //系统提供的默认=运算符实施的也是浅拷贝
- //s3.str_ = s2.str; 逐个会员赋值
- //s3 = s2;
- //s3.operator = (s2);
- return 0;
- }
- //
- //赋值操作,=运算符的重载
- //独一无二的对象禁止拷贝
运行结果:
转载于:https://blog.51cto.com/liam2199/1175611