深入C++的拷贝构造和赋值函数 (深拷贝,浅拷贝)
来源:互联网 发布:怎样查询电信网络密码 编辑:程序博客网 时间:2024/06/05 15:09
说明
拷贝构造函数是一种特殊的构造函数。相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。
函数的名称必须和类名称一致。
它的参数是唯一的,该参数是const类型的引用变量。例如
类X的拷贝构造函数的形式为X(X& x)。
Q:为啥拷贝构造函数的参数必须是同类对象的引用,而不能是值传递?
请看下面的例子:
- class A{
- public:
- A(A copy); //(1)
- A(const& other); //(2)
- // ...
- };
- A a1;
- A a2 = a1;
一:如果拷贝构造函数允许值传递,那么就会与引用传递产生二义性。程序无法判断该调用(1)还是(2)。
二:(1)形式的拷贝构造函数实际上是非法的。这个拷贝构造函数在参数传递的过程中要调用拷贝构造函数本身,值传递又得调用拷贝构造函数本身,于是乎就陷入了无限递归之中。即会一直copy下去,因此,A(A copy)语法错误,在c++中不允许。
使用
当类的对象需要拷贝时,拷贝构造函数将会被调用。以下情况都会调用拷贝构造函数:
一个对象以值传递的方式传入函数体
一个对象以值传递的方式从函数返回
一个对象需要通过另外一个对象进行初始化。
如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的浅拷贝。
拷贝构造函数 vs 拷贝赋值函数
拷贝赋值函数参数跟拷贝构造函数相同,两者的区别在于:
构造函数是对象创建并用另一个已经存在的对象来初始化它。
赋值函数只能把一个对象赋值给另一个已经存在的对象。
- A a1(“hi”);
- A a2(“hello”)
- A a3(a1); //<span style="font-family: Arial, Helvetica, sans-serif;">调用构造函数</span>
- a3 = a2; //调用赋值函数
浅拷贝 vs 深拷贝
深拷贝和浅拷贝可以简单理解为:
如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝。
反之,没有重新分配资源,只是对对象中的数据成员进行简单的赋值,就是浅拷贝。默认拷贝构造函数执行的也是浅拷贝。
下面举个深拷贝的例子。
- #include <iostream>
- using namespace std;
- class CA{
- public:
- CA(intb,char* cstr){
- a=b;
- str=newchar[b];
- strcpy(str,cstr);
- }
- CA(constCA& C){
- a=C.a;
- str=newchar[a]; //深拷贝
- if(str!=0)
- strcpy(str,C.str);
- }
- voidShow(){
- cout<<str<<endl;
- }
- ~CA(){
- deletestr;
- }
- private:
- int a;
- char *str;
- };
- int main(){
- CAA(10,"Hello!");
- CA B=A;
- B.Show();
- return 0;
- }
Q:有了浅拷贝,为啥还出现了深拷贝呢?
在某些状况下,类内成员变量需要动态开辟堆内存,如果实行浅拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,错误就来了。
废话少说,挣个有用的。
- class Test{
- public:
- Test(const char *str ="");//构造函数
- Test(const Test& copy); //拷贝构造函数
- Test& operator = (const Test& assign); //拷贝构造函数
- ~Test(); //析构函数
- private:
- size_t m_size; //字符串的长度
- char *m_data; //字符串指针
- } ;
i、将a赋值给b,即b.m_data = a.m_data。这就会造成错误,如下图所示:
1、b.m_data 原有内存没有释放,造成内存泄露。
2、b.m_data 和 a.m_data指向了同一块内存,任何一方变动都会影响另一方。
3、对象析构时,m_data析构了两次。
ii、拷贝构造也是同样的道理
两个成员变量指针也指向同一块内存。当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。
下面给出一种比较靠谱的实现:
- Test(const char *str = ""){
- if(!str){
- m_data = new char[1];
- *m_data = '\0';
- m_size = 0;
- }else{
- int len = strlen(str);
- m_data = new char[len+1];
- strcpy(m_data,str);
- m_size = len;
- }
- }
- Test(const Test& copy){
- int len = strlen(copy.m_data);
- m_data = new char[len+1];//深拷贝
- strcpy(m_data,copy.m_data);
- m_size = len;
- }
- Test& operator = (const Test& assign){
- if(this != assign){
- int len = strlen(assign.m_data);
- char *temp = newchar[len+1];//深拷贝
- strcpy(temp,assign.m_data);
- delete [] m_data;
- m_data = temp;
- m_size = len;
- temp = NULL;
- }
- return *this;
- }
- ~Test(){
- delete [] m_data;
- }
- 深入C++的拷贝构造和赋值函数 (深拷贝,浅拷贝)
- 深入C++的拷贝构造和赋值函数 (深拷贝,浅拷贝)
- 拷贝构造函数与赋值函数;深拷贝,浅拷贝
- 拷贝构造函数(深拷贝和浅拷贝)
- 拷贝构造函数(浅拷贝和深拷贝)
- c++拷贝构造函数(深拷贝和浅拷贝)
- c++拷贝构造函数(浅拷贝和深拷贝)
- c++中 拷贝构造函数的深拷贝和浅拷贝--“浅拷贝”与“深拷贝”
- 拷贝构造函数与赋值构造函数 浅拷贝和深拷贝
- Day40、this指针和常函数、析构函数、对象的创建和销毁过程、拷贝构造和拷贝赋值(深拷贝、浅拷贝!)
- C++的拷贝构造函数(深拷贝、浅拷贝)
- 拷贝构造函数和拷贝赋值函数
- 【C++】拷贝构造函数和赋值函数
- 拷贝构造函数和赋值的深入理解
- 类的赋值函数和拷贝构造函数以及深、浅拷贝问题
- 5.c++-拷贝构造函数(深拷贝,浅拷贝)
- c++_拷贝构造函数/浅拷贝/深拷贝
- 拷贝构造函数,类的赋值运算符重载,深拷贝与浅拷贝
- NYOJ 题目330一个简单的数学题(数学)
- [LeetCode OJ] Word Break 解题报告
- php绝对路径与相对路径之间关系的的深入研究
- Machine Learning Notes - PLA
- 栈与队列的实现__ 两个栈实现队列 vs 两个队列实现栈
- 深入C++的拷贝构造和赋值函数 (深拷贝,浅拷贝)
- Kinect for Windows SDK v2.0 开发笔记 (十一) 高清面部帧(2) 面部特征对齐
- android:padding和android:margin的区别
- 一元高次方程的求解
- Direct2D 1.1 开发笔记 特效篇(二) 简单的自定义特效
- 天天天天天天天天天天天天天天天天天天天天天天天天
- 哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈
- 更好哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈
- 么么么么么么么么么么么么么么么么么么么么么么