網站首頁 編程語言 正文
三種拷貝方式
淺拷貝
對于自定義的string類,如果不顯式定義拷貝構造函數,編譯器會默認生成拷貝構造函數,此時的拷貝方式是淺拷貝,兩個對象會公用一塊兒內存,析構時同一空間被釋放兩次,會導致程序崩潰。
賦值運算符重載也會產生同樣的問題,同時,由于被賦值對象原來有空間,淺拷貝還會導致舊的空間無法找到,造成內存泄漏。
深拷貝
類中設計到資源的管理,拷貝構造函數、賦值運算符重載以及析構函數都要顯示給出,按照深拷貝的方式。
深拷貝的方式讓每個對象都獨立擁有一份資源,不會造成多次釋放導致程序崩潰的問題。
寫時拷貝
寫時拷貝是通過淺拷貝+引用計數的方式來實現的,引用計數是用來記錄資源的被引用的次數,
可以將這種寫時拷貝的機制想象成“拖延癥”,只有當不得不進行拷貝時,才會開辟新空間進行拷貝
VS與GCC中的拷貝方式
Windows VS2022
VS中采用的是深拷貝的方式
Linux GCC
GCC編譯器采用的是寫時拷貝的方式
簡易string類
簡易string類主要實現四個功能,即構造函數、拷貝構造函數、析構函數、賦值運算符重載,主要考察深淺拷貝
實現簡易string類有兩種代碼風格,一種傳統版寫法,代碼復用性第,可讀性較好;另一種稱為現代版寫法,代碼復用性高,但是較難理解。
傳統版寫法的string類
構造函數
步驟:
- 判斷是否為空指針,string類不允許nullptr構造對象
- 申請新空間
- 將字符串中的值拷貝到申請的空間
string(const char* str = "")
{
if (nullptr == str)
{
assert(false);
return;
}
//+1是因為有'\0',strcpy會將源字符串中的'\0'拷貝到目標空間
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
拷貝構造函數
步驟:
- 開辟空間
- 用源對象的_str給當前對象的_str賦值
string(const string& s)
:_str(new char[strlen(s._str) + 1])
{
strcpy(_str, s._str);
}
賦值運算符重載
步驟:
- 判斷是否自己給自己賦值
- 開辟新空間
- 拷貝元素
- 刪除舊空間
string& operator=(const string& s)
{
//避免自己給自己賦值
if (this != &s)
{
char* temp = new char[strlen(s._str) + 1];
strcpy(temp, s._str);
delete[] _str;
_str = temp;
}
return *this;
}
另一種寫法
這種寫法不用定義臨時變量,代碼相對簡潔一點,但是如果new申請空間失敗,舊的空間也無法找到。
析構函數
步驟:
- 釋放空間
- 將指針置為空
~string()
{
?? ?if (_str)
?? ?{
?? ??? ?delete[]_str;
?? ??? ?_str = nullptr;
?? ?}
}
?
現代版寫法string類
構造函數
string(const char* str = "")
{
if (str == nullptr)
{
assert(false);
}
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
拷貝構造函數
拷貝構造函數中利用構造函數,實現了代碼的復用
步驟:
- 在初始化列表中將_str置為空
- 定義一個臨時的string類對象,指向要拷貝的對象相同位置
- 交換臨時對象與當前對象的_str
string(const string& s)
:_str(nullptr)
{
//調用構造函數
string temp(s._str);
//交換以后temp指向空,函數退出后被銷毀
swap(_str, temp._str);
}
賦值運算符重載函數
步驟:
- 判斷是否為自己給自己賦值
- 調用拷貝構造函數定義臨時變量
- 交換臨時變量與當前對象的_str
string& operator=(string& s)
{
if (this != &s)
{
string temp(s);
swap(_str, s._str);
}
return *this;
}
更簡潔的寫法:
string& operator=(string s)
{
//傳參調用拷貝構造函數,不用判斷是否給自己賦值
swap(_str, s._str);
return *this;
}
析構函數
~string()
{
if (_str)
{
delete[] _str;
_str = nullptr;
}
}
總結
原文鏈接:https://blog.csdn.net/qq_44631587/article/details/126271106
相關推薦
- 2021-12-07 C語言系統調用約定_C 語言
- 2022-07-31 C++超詳細分析講解內聯函數_C 語言
- 2022-04-01 mybatis if 并且判斷列表是否為空
- 2022-12-24 Kotlin?Channel處理多個數據組合的流_Android
- 2023-12-08 antd 表單校驗問題
- 2022-07-24 C++超詳細講解樹與二叉樹_C 語言
- 2022-07-18 Qt和Windows消息通信機制
- 2022-10-23 Go?數據結構之堆排序示例詳解_Golang
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支