C++深拷贝与浅拷贝探讨

对于普通类型的对象来说,它们之间的复制是很简单的,例如:
int a=88;
int b=a; 
而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。下面看一个类对象拷贝的简单例子。 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;
 
class CExample {
private:
     int a;
public:
     CExample(int b)
     { a=b;}
     void Show ()
     {
        cout<<a<<endl;
    }
};
 
int main()
{
     CExample A(100);
     CExample B=A;
     B.Show ();
     return 0;
}

 运行程序,屏幕输出100。从以上代码的运行结果可以看出,系统为对象B分配了内存并完成了与对象A的复制过程。就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。下面举例说明拷贝构造函数的工作过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
using namespace std;
 
class CExample {
private:
    int a;
public:
    CExample(int b)
    { a=b;}
     
    CExample(const CExample& C)
    {
        a=C.a;
    }
    void Show ()
    {
        cout<<a<<endl;
    }
};
 
int main()
{
    CExample A(100);
    CExample B=A;
    B.Show ();
    return 0;
}

当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用以下情况都会调用拷贝构造函数:

(1)一个对象以值传递的方式传入函数体 
(2)一个对象以值传递的方式从函数返回 
(3)一个对象需要通过另外一个对象进行初始化

如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝,后面将进行说明。

自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。

浅拷贝和深拷贝

  在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。

  深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。下面举个深拷贝的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
using namespace std;
class CA
{
 public:
  CA(int b,char* cstr)
  {
   a=b;
   str=new char[b];
   strcpy(str,cstr);
  }
  CA(const CA& C)
  {
   a=C.a;
   str=new char[a];//深拷贝
   if(str!=0)
    strcpy(str,C.str);
  }
  void Show()
  {
   cout<<str<<endl;
  }
  ~CA()
  {
   delete str;
  }
 private:
  int a;
  char *str;
};
 
int main()
{
 CA A(10,"Hello!");
 CA B=A;
 B.Show();
 return 0;
}

 来总结一下关于 深拷贝与浅拷贝需要知道的基本概念和知识:

(1)什么时候用到拷贝函数?

  a.一个对象以值传递的方式传入函数体; 
  b.一个对象以值传递的方式从函数返回;
  c.一个对象需要通过另外一个对象进行初始化。

如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝

(2)是否应该自定义拷贝函数?

(3)什么叫深拷贝?什么是浅拷贝?两者异同?

自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。

 如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。

 (4)深拷贝好还是浅拷贝好?

如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。


### C++深拷贝浅拷贝的区别及用法 #### 概念区分 在 C++ 编程中,当涉及到对象的状态包含其他对象的引用时,深拷贝浅拷贝的概念显得尤为重要。浅拷贝仅复制指向数据的指针或其他引用类型的变量,而不会创建新的内存区域来存储实际的数据副本;相比之下,深拷贝不仅复制指针或引用本身,还会分配新的堆区空间并将原始数据完全复制过去[^1]。 具体来说: - **浅拷贝**是指简单地将一个对象的内容逐字节复制到另一个新对象上。如果该对象内部包含了动态分配的资源(如通过 `new` 创建的对象),那么这些资源只会被其地址值所复制,而不是真正意义上的内容复制[^2]。 - **深拷贝**则意味着不仅要复制对象本身的字段,还需要为那些由原对象管理的所有外部资源重新申请相应的内存,并完成完整的数据迁移过程[^3]。 #### 使用场景分析 根据不同的应用场景需求可以选择适合自己的策略: 1. 当两个独立实例之间不需要共享某些特定成员变量(尤其是涉及动态分配部分),此时应该采用深拷贝机制以确保各自拥有单独的一份数据副本; 2. 如果多个对象可以安全共存于同一块物理存储之上,则可考虑利用效率更高的浅拷贝方法减少不必要的开销[^4]. #### 实现方式探讨 为了正确处理上述两种情况下的行为差异,在定义类时通常需要重载以下几个特殊成员函数之一或者全部三个: - 构造函数:用于初始化新创建的对象; - 赋值运算符(`operator=`):负责已存在目标对象更新源操作数表示的新状态; - 析构函数(destructor) :清理当前实例占用的一切非托管型资源. 下面给出一段示范代码展示如何实现自定义版本中的深拷贝逻辑: ```cpp class MyClass { private: int* data; // 动态分配整数数组 public: // 默认构造函数 MyClass(int size){ this->data = new int[size]; std::fill_n(this->data, size, 0); } // 复制构造函数 - 执行深拷贝 MyClass(const MyClass& other){ this->data = new int[other.getSize()]; std::copy(other.data, other.data + getSize(), this->data); } ~MyClass(){ delete[] data; } int getSize() const {return sizeof(data)/sizeof(*data);} }; ``` 以上例子展示了如何在一个简单的类结构里加入必要的措施防止因不当使用而导致意外后果的发生。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值