C语言中深拷贝和写时拷贝的图文详解是怎样的?

2026-04-18 22:292阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1209个文字,预计阅读时间需要5分钟。

C语言中深拷贝和写时拷贝的图文详解是怎样的?

前言:之前我们讨论了6个成员函数中提到的深浅拷贝问题,现在再首推一一梳理。

一、深浅拷贝哪家强?先给出代码,再理解原理。

pythonimport copy

class A: def __init__(self, value): self.value=value self.list=[1, 2, 3]

a=A([1, 2, 3])b=copy.deepcopy(a)c=copy.copy(a)

浅拷贝a.list[0]=0print(b.list) # 输出:[1, 2, 3]print(c.list) # 输出:[0, 2, 3]

深拷贝b.value=10print(a.value) # 输出:[1, 2, 3]print(b.value) # 输出:10

通过以上代码,我们可以看出:- 浅拷贝只会拷贝对象本身,对于对象中的可变对象(如列表、字典等),只会拷贝其引用。- 深拷贝会递归拷贝对象中的所有可变对象,生成一个全新的对象。

总结:深拷贝比浅拷贝更安全,但性能较差。在实际应用中,应根据具体需求选择合适的拷贝方式。

前言

之前我们在浅谈6个成员函数中有提到深浅拷贝的问题,现在再回首掏一把。

一、深浅拷贝哪家强?

先给出代码理一理

#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> #include<assert.h> using namespace std; class String { friend ostream& operator<<(ostream &out, const String &s); public: String(const char* str = "") { m_data = new char[strlen(str) + 1]; strcpy(m_data, str); } //String(const String& s)//qian拷贝 //{ // m_data = s.m_data; //} String(const String& s)//深拷贝 { m_data = new char[strlen(s.m_data) + 1]; strcpy(m_data, s.m_data); } String& operator=(const String& s) { if (this != &s) { delete[]m_data; m_data = new char[strlen(s.m_data) + 1]; strcpy(m_data, s.m_data); } return *this; } ~String() { delete[]m_data; m_data = nullptr; } private: char* m_data; }; ostream& operator<<(ostream &out, const String &s) { out << s.m_data; return out; } void main() { String s1("abc"); String s2 = s1; cout << "s1 = " << s1 << endl; cout << "s2 = " << s2 << endl; }

而我们之前所说的浅拷贝崩溃是因为doublefree的问题,因此我们可以定义一个引用计数器,来记录当前使用该值的对象数,如果数目大于1,则不释放内存。

class String { friend ostream& operator<<(ostream &out, const String &s); public: String(const char* str = "") { m_data = new char[strlen(str) + 1]; strcpy(m_data, str); m_count++; } String(const String& s)//浅拷贝 { m_data = s.m_data; m_count++; } String& operator=(const String& s) { if (this != &s) { m_data = s.m_data; m_count++; } return *this; } ~String()//浅赋值 { if (--m_count == 0) { delete[]m_data; m_data = nullptr; } } private: char* m_data; static int m_count;//引用计数器 }; int String::m_count = 0; ostream& operator<<(ostream &out, const String &s) { out << s.m_data; return out; } void main() { String s1("abc"); String s2 = s1; String s3; s3 = s2; cout << "s1 = " << s1 << endl; cout << "s2 = " << s2 << endl; cout << "s3 = " << s3 << endl; }

可以看出,三个对象的m_data共享同一块内存空间,节省了资源;

C语言中深拷贝和写时拷贝的图文详解是怎样的?

但是暴露出了很多的问题:站在对象的角度,其中一个对象改变m_data其他的对象也会随之改变;其二若s3使用其他字符串初始化,但计数器还是三者共享。

倘若我们使用深拷贝方法,就不会出现这种问题。如果可以在不改变m_data前使用浅拷贝,在改变时使用深拷贝,暨同时实现深浅拷贝,那么就两全其美。

二、写时拷贝

通过对上面问题的分析,我们需要实现:引用计数器管理不同的空间。

class String_rep { public: String_rep(const char* str = "") :m_count(0) { m_data = new char[strlen(str) + 1]; strcpy(m_data, str); cout << "creat" << endl; } String_rep(const String_rep &rep) :m_count(0) { m_data = rep.m_data; increment(); } String_rep & operator=(const String_rep &rep) { if (this != &rep) { m_data = rep.m_data; increment(); } return *this; } public: void increment() {m_count++;} void decrement() {m_count--;} private: char* m_data; int m_count; }; class String { public: String(const char* str = "") :pn(new String_rep(str)) { pn->increment(); } ~String() { cout << "Free" << endl; } private: String_rep *pn; }; void main() { String s1("abc"); }

拷贝构造:s1和s2管理同一块空间

定义s3,和s1、s2没有关联;

我们再完全理一遍:

此时已经解决我们之前提到过的第二个问题。

再来看第一个问题:

s1的改变影响了s2;

写时拷贝:需要改变的时候深拷贝。

void to_upper() { String_rep *new_pn = new String_rep(pn->Getdata());//创建新空间 pn->decrement();//原空间计数器减一 pn = new_pn;//需要更改的对象的pn指向新空间 pn->increment();//新空间的计数器加一 char* p = pn->Getdata(); while (*p != '\0') { if (*p >= 'a' && *p <= 'z') *p -= 32; p++; }

总结

到此这篇关于C++深浅拷贝和写时拷贝的文章就介绍到这了,更多相关C++深浅拷贝 写时拷贝内容请搜索自由互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持自由互联!

本文共计1209个文字,预计阅读时间需要5分钟。

C语言中深拷贝和写时拷贝的图文详解是怎样的?

前言:之前我们讨论了6个成员函数中提到的深浅拷贝问题,现在再首推一一梳理。

一、深浅拷贝哪家强?先给出代码,再理解原理。

pythonimport copy

class A: def __init__(self, value): self.value=value self.list=[1, 2, 3]

a=A([1, 2, 3])b=copy.deepcopy(a)c=copy.copy(a)

浅拷贝a.list[0]=0print(b.list) # 输出:[1, 2, 3]print(c.list) # 输出:[0, 2, 3]

深拷贝b.value=10print(a.value) # 输出:[1, 2, 3]print(b.value) # 输出:10

通过以上代码,我们可以看出:- 浅拷贝只会拷贝对象本身,对于对象中的可变对象(如列表、字典等),只会拷贝其引用。- 深拷贝会递归拷贝对象中的所有可变对象,生成一个全新的对象。

总结:深拷贝比浅拷贝更安全,但性能较差。在实际应用中,应根据具体需求选择合适的拷贝方式。

前言

之前我们在浅谈6个成员函数中有提到深浅拷贝的问题,现在再回首掏一把。

一、深浅拷贝哪家强?

先给出代码理一理

#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> #include<assert.h> using namespace std; class String { friend ostream& operator<<(ostream &out, const String &s); public: String(const char* str = "") { m_data = new char[strlen(str) + 1]; strcpy(m_data, str); } //String(const String& s)//qian拷贝 //{ // m_data = s.m_data; //} String(const String& s)//深拷贝 { m_data = new char[strlen(s.m_data) + 1]; strcpy(m_data, s.m_data); } String& operator=(const String& s) { if (this != &s) { delete[]m_data; m_data = new char[strlen(s.m_data) + 1]; strcpy(m_data, s.m_data); } return *this; } ~String() { delete[]m_data; m_data = nullptr; } private: char* m_data; }; ostream& operator<<(ostream &out, const String &s) { out << s.m_data; return out; } void main() { String s1("abc"); String s2 = s1; cout << "s1 = " << s1 << endl; cout << "s2 = " << s2 << endl; }

而我们之前所说的浅拷贝崩溃是因为doublefree的问题,因此我们可以定义一个引用计数器,来记录当前使用该值的对象数,如果数目大于1,则不释放内存。

class String { friend ostream& operator<<(ostream &out, const String &s); public: String(const char* str = "") { m_data = new char[strlen(str) + 1]; strcpy(m_data, str); m_count++; } String(const String& s)//浅拷贝 { m_data = s.m_data; m_count++; } String& operator=(const String& s) { if (this != &s) { m_data = s.m_data; m_count++; } return *this; } ~String()//浅赋值 { if (--m_count == 0) { delete[]m_data; m_data = nullptr; } } private: char* m_data; static int m_count;//引用计数器 }; int String::m_count = 0; ostream& operator<<(ostream &out, const String &s) { out << s.m_data; return out; } void main() { String s1("abc"); String s2 = s1; String s3; s3 = s2; cout << "s1 = " << s1 << endl; cout << "s2 = " << s2 << endl; cout << "s3 = " << s3 << endl; }

可以看出,三个对象的m_data共享同一块内存空间,节省了资源;

C语言中深拷贝和写时拷贝的图文详解是怎样的?

但是暴露出了很多的问题:站在对象的角度,其中一个对象改变m_data其他的对象也会随之改变;其二若s3使用其他字符串初始化,但计数器还是三者共享。

倘若我们使用深拷贝方法,就不会出现这种问题。如果可以在不改变m_data前使用浅拷贝,在改变时使用深拷贝,暨同时实现深浅拷贝,那么就两全其美。

二、写时拷贝

通过对上面问题的分析,我们需要实现:引用计数器管理不同的空间。

class String_rep { public: String_rep(const char* str = "") :m_count(0) { m_data = new char[strlen(str) + 1]; strcpy(m_data, str); cout << "creat" << endl; } String_rep(const String_rep &rep) :m_count(0) { m_data = rep.m_data; increment(); } String_rep & operator=(const String_rep &rep) { if (this != &rep) { m_data = rep.m_data; increment(); } return *this; } public: void increment() {m_count++;} void decrement() {m_count--;} private: char* m_data; int m_count; }; class String { public: String(const char* str = "") :pn(new String_rep(str)) { pn->increment(); } ~String() { cout << "Free" << endl; } private: String_rep *pn; }; void main() { String s1("abc"); }

拷贝构造:s1和s2管理同一块空间

定义s3,和s1、s2没有关联;

我们再完全理一遍:

此时已经解决我们之前提到过的第二个问题。

再来看第一个问题:

s1的改变影响了s2;

写时拷贝:需要改变的时候深拷贝。

void to_upper() { String_rep *new_pn = new String_rep(pn->Getdata());//创建新空间 pn->decrement();//原空间计数器减一 pn = new_pn;//需要更改的对象的pn指向新空间 pn->increment();//新空间的计数器加一 char* p = pn->Getdata(); while (*p != '\0') { if (*p >= 'a' && *p <= 'z') *p -= 32; p++; }

总结

到此这篇关于C++深浅拷贝和写时拷贝的文章就介绍到这了,更多相关C++深浅拷贝 写时拷贝内容请搜索自由互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持自由互联!