c++之深拷贝和浅拷贝

本文详细解析了拷贝构造函数的概念及其在对象复制中的作用,区分了浅拷贝与深拷贝的不同,并提供了具体的代码示例,帮助读者深入理解C++中的拷贝构造机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、拷贝构造函数

拷贝构造函数是什么?

当用另一个对象来实例化一个新的对象时,调用的不是我们之前定义的普通构造函数,而是调用拷贝构造函数。我们可以拷贝构造函数中将要拷贝的对象的一些数组成员复制新的实例化对象。

简而言之,拷贝构造函数用于对象的复制。

定义格式
类名(const 类名&变量名)

Student(const Student &stu) //其中stu是被拷贝的对象变量名

Student stu1;
Student stu2=stu1;//执行拷贝构造函数
Student stu3(stu1);//执行拷贝构造函数

二、浅拷贝

浅拷贝就是简单的复制数据成员

class Student
{
	public:
		Student();
		Student(const Student& stu){
		age=stu.age;
		score=stu.score;
	}
	private:
		int age;
		int score;
};

三、深拷贝

深拷贝涉及到数据成员是指针,为了不让拷贝后的指针指向同一片区域,我们不能简单地把指针拷贝,而是拷贝指针指向的内存的内容

class Student
{
public:
	Student()
	Student(const Student& stu){
		age=stu.age;
		subjectsScore = new int[7];
		for(int i=0;i<7;i++)
		{subjectsScore[i]=stu.subjectsScore[i];}
	}
private:
	int age;
	int *subjectsScore;
};

补充

拷贝构造函数什么时候调用

  • 用一个对象去初始化另一个对象时候调用拷贝构造函数
  • 当类对象作为形参时候,会调用拷贝构造函数
  • 当类对象作为返回值的时候,会拷贝构造函数

这就是为什么拷贝构造函数里面要用引用
Student(const Student &stu)
如果不用引用去定义拷贝构造函数,那么对象作为形参又会调用拷贝构造函数,如此套娃,就不行了。

### C++深拷贝浅拷贝的区别及实现方法 #### 深拷贝浅拷贝的概念 在 C++ 中,当一个类的对象被复制时,默认情况下会执行浅拷贝。这意味着仅对象中的成员变量会被简单地逐位复制到新的对象中。如果这些成员变量是指针,则只会复制指针本身,而不是它所指向的数据[^1]。 相比之下,深拷贝不仅复制指针本身,还会分配新的内存并复制指针所指向的数据内容。这样可以确保源对象目标对象之间没有任何共享的动态资源[^2]。 --- #### 浅拷贝的特点及其潜在问题 浅拷贝通常由编译器自动提供,在这种模式下,两个对象可能共同拥有某些堆上的数据结构。一旦其中一个对象销毁其拥有的堆资源(通过析构函数),另一个对象可能会尝试访问已被释放的内存区域,从而引发未定义行为[^3]。 例如: ```cpp class Test { public: int* ptr; Test(int value) : ptr(new int(value)) {} ~Test() { delete ptr; } }; void example() { Test t1(10); Test t2 = t1; // 默认调用了浅拷贝 // 此处存在隐患:t1 t2 的 ptr 都指向同一块内存 } ``` 上述代码片段展示了如何因浅拷贝而导致双重删除的问题[^4]。 --- #### 实现深拷贝的方法 为了防止浅拷贝带来的风险,开发者需要显式重载拷贝构造函数以及赋值运算符 (`operator=`),以便能够安全地管理动态分配的资源。以下是具体实现: ##### 使用自定义拷贝构造函数 下面是一个典型的例子,展示了一个支持深拷贝的 `Person` 类的设计: ```cpp #include <iostream> using namespace std; class Person { private: string name; int* age; public: // 构造函数 Person(string n, int a) : name(n), age(new int(a)) {} // 自定义拷贝构造函数 Person(const Person& other) : name(other.name), age(new int(*(other.age))) { cout << "Deep copy constructor called." << endl; } // 赋值运算符重载 Person& operator=(const Person& other) { if (this != &other) { this->name = other.name; *(this->age) = *(other.age); // 或者重新分配内存以避免覆盖原有数据 } return *this; } // 析构函数 ~Person() { delete age; cout << "Destructor called for " << name << "." << endl; } void displayInfo() const { cout << "Name: " << name << ", Age: " << *age << endl; } }; ``` 在这个版本中,无论是通过拷贝构造还是赋值操作创建的新实例都会获得一份独立于原对象之外的副本[^2]。 --- #### 示例程序验证效果 考虑如下测试场景: ```cpp int main() { Person p1("Alice", 30); p1.displayInfo(); Person p2 = p1; // 调用拷贝构造函数 p2.displayInfo(); p2.*age += 5; // 修改 p2 不会影响 p1 p1.displayInfo(); p2.displayInfo(); return 0; } ``` 运行结果表明两者的内部状态互不影响,证明实现了真正的深拷贝关系[^3]。 --- #### 注意事项 - 如果某个类不涉及任何动态内存分配或者所有成员均为基本类型/标准库容器,则无需担心浅拷贝问题。 - 对于复杂情况下的大型项目开发过程中,建议优先采用现代 C++ 提供的技术手段如智能指针(`std::unique_ptr`, `std::shared_ptr`)代替原始裸指针来简化生命周期管理减少错误发生几率[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值