vector拷贝说的道理

偶然在群里聊到这个了,感觉这个切口对于理解OOP**“封装”**这个概念颇为重要

以下内容由d老师辅助生成,本人整理

浅拷贝与深拷贝区分、

1. 浅拷贝(Shallow Copy)

  • 直接复制成员的值:将对象的成员变量(包括指针)逐字节复制到新对象。
  • 指针共享内存:新旧对象的指针成员指向同一块内存地址。

例如 默认的拷贝构造函数动态分配的数组 or 指针逐字节复制

特性

  • 当某个类一个对象析构时,另一个也会被析构,同时释放两次内存
  • 通过指针实现的拷贝复制,修改会直接影响另一方
1
2
3
4
5
6
7
class Data {
public:
int* arr;
int size;
Data(int n) : size(n) { arr = new int[n]; }
~Data() { delete[] arr; } // 析构函数释放内存
};

2. 深拷贝(Deep Copy)

  • 独立复制资源:为新对象分配新的内存,并复制原对象指针指向的所有内容。
  • 资源完全独立:新旧对象的指针指向不同的内存区域。

例如 copy方法

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
class Data {
public:
int* arr;
int size;
Data(int n) : size(n) { arr = new int[n]; }

// 自定义拷贝构造函数(深拷贝)
Data(const Data& other) : size(other.size) {
arr = new int[size];
std::copy(other.arr, other.arr + size, arr);
}

// 自定义赋值运算符(深拷贝)
Data& operator=(const Data& other) {
if (this != &other) {
delete[] arr; // 释放原有内存
size = other.size;
arr = new int[size];
std::copy(other.arr, other.arr + size, arr);
}
return *this;
}

~Data() { delete[] arr; }
};

特点

  • 安全性d1d2 析构时不会冲突。
  • 独立性:修改 d1.arr 不会影响 d2.arr

下面是几个常见的拷贝方案

1. 拷贝构造函数

1
2
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2(v1); // 直接拷贝构造

浅拷贝

2. 重载赋值运算符(=)

1
2
3
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2;
v2 = v1; // 赋值操作

浅拷贝

3. 范围构造函数

1
2
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2(v1.begin(), v1.end()); // 拷贝整个v1

元素级别的拷贝行为

  • 如果元素是值类型(如 intdoublestd::string),会直接复制值,新旧 vector 中的元素完全独立。
  • 如果元素是指针类型(如 int*),则会复制指针的值(浅拷贝),导致新旧 vector 的指针指向同一块内存。

4.std::copy 算法 + back_inserter

1
2
3
4
5
#include <algorithm> // 需要头文件
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2;

std::copy(v1.begin(), v1.end(), std::back_inserter(v2));

深拷贝

建议预先调用v2.reserve(v1.size()) 避免多次扩容

5. assign() 方法

覆盖内容拷贝常用

1
2
3
4
5
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2;

//通过迭代器范围赋值,本质属于替换元素内容
v2.assign(v1.begin(), v1.end());

深拷贝

其中有任何一个实参是指向 *this 中的迭代器时行为未定义

6. insert() 方法

1
2
3
4
5
6
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = {4, 5};

// 将v1的全部内容插入到v2的末尾
v2.insert(v2.end(), v1.begin(), v1.end());
// v2 变为 {4, 5, 1, 2, 3}

插入拷贝