《C++》STL--string详解(下)
文章目录
- 一、深浅拷贝定义
- 1.1 浅拷贝的本质
- 1.2 内存示意图
- 1.3 深拷贝的本质
- 1.4 内存示意图
- 二、用拷贝实现string类
- 2.1 浅拷贝实现的String类
- 2.2 深拷贝实现的String类
- 2.3 总结
一、深浅拷贝定义
1.1 浅拷贝的本质
- 浅拷贝就像复印一张名片时,只复制了名片上的地址信息,而没有复制地址对应的实际房屋。在C++中表现为:
class ShallowString {
public:char* data;// 构造函数ShallowString(const char* str = "") {data = new char[strlen(str)+1];strcpy(data, str);}// 问题:没有自定义拷贝构造函数
};ShallowString s1("hello");
ShallowString s2 = s1; // 默认浅拷贝
1.2 内存示意图
s1.data → "hello\0"↑
s2.data ───┘
1.3 深拷贝的本质
- 深拷贝则是完全复制整栋房屋。在C++中需要显式实现:
class DeepString {
public:char* data;// 构造函数DeepString(const char* str = "") {data = new char[strlen(str)+1];strcpy(data, str);}// 深拷贝构造函数DeepString(const DeepString& other) {data = new char[strlen(other.data)+1];strcpy(data, other.data);}
};DeepString s1("hello");
DeepString s2 = s1; // 深拷贝
1.4 内存示意图
s1.data → "hello\0"
s2.data → "hello\0" // 完全独立的内存
可见,用大白话来说,深拷贝就是拥有自己的内存,而浅拷贝非也
二、用拷贝实现string类
2.1 浅拷贝实现的String类
#include <cstring>
#include <iostream>class ShallowString {
private:char* m_data;size_t m_size;public:// 构造函数ShallowString(const char* str = "") {m_size = strlen(str);m_data = new char[m_size + 1];strcpy(m_data, str);}// 析构函数~ShallowString() {delete[] m_data;}// 打印字符串内容void print() const {std::cout << m_data << std::endl;}// 修改字符串内容void modify(size_t pos, char c) {if (pos < m_size) {m_data[pos] = c;}}
};void demoShallowCopyProblem() {ShallowString s1("hello");ShallowString s2 = s1; std::cout << "修改前:" << std::endl;s1.print(); // 输出: hellos2.print(); // 输出: hellos2.modify(0, 'H'); // 修改s2std::cout << "修改后:" << std::endl;s1.print(); // 输出: Hello (不应该被修改)s2.print(); // 输出: Hello}
当然,本文单开肯定也是有道理的,上面的代码是错误的awa, 因为在程序结束时会导致双重释放错误!
-
浅拷贝问题分析:
-
拷贝时只复制了指针值,导致多个对象共享同一内存
-
修改一个对象会影响其他对象
-
析构时会导致同一内存被多次释放
-
2.2 深拷贝实现的String类
那么正确的版本,在下文
class DeepString {
private:char* m_data;size_t m_size;public:// 构造函数DeepString(const char* str = "") {m_size = strlen(str);m_data = new char[m_size + 1];strcpy(m_data, str);}// 拷贝构造函数(深拷贝)DeepString(const DeepString& other) {m_size = other.m_size;m_data = new char[m_size + 1];strcpy(m_data, other.m_data);}// 拷贝赋值运算符(深拷贝)DeepString& operator=(const DeepString& other) {if (this != &other) { // 防止自赋值delete[] m_data; // 释放原有内存m_size = other.m_size;m_data = new char[m_size + 1];strcpy(m_data, other.m_data);}return *this;}// 析构函数~DeepString() {delete[] m_data;}// 打印字符串内容void print() const {std::cout << m_data << std::endl;}// 修改字符串内容void modify(size_t pos, char c) {if (pos < m_size) {m_data[pos] = c;}}
};// 演示深拷贝的正确性
void demoDeepCopy() {DeepString s1("hello");DeepString s2 = s1; // 深拷贝std::cout << "修改前:" << std::endl;s1.print(); // 输出: hellos2.print(); // 输出: hellos2.modify(0, 'H'); // 修改s2std::cout << "修改后:" << std::endl;s1.print(); // 输出: hello (不受影响)s2.print(); // 输出: Hello// 程序结束时正确释放内存
}
2.3 总结
-
必须自定义拷贝构造函数和拷贝赋值运算符
-
在拷贝时分配新内存并复制内容
-
注意处理自赋值情况