C++:string容器(下篇)

1.string淺拷貝的問題

// 為了和標準庫區分,此處使用String
class String
{
public :/*String():_str(new char[1]){*_str = '\0';}*///String(const char* str = "\0") // 錯誤示范//String(const char* str = nullptr) // 錯誤示范String(const char* str = ""){if (nullptr == str){assert(false);return;} _str = new char[strlen(str) + 1];strcpy(_str, str);   }~String(){if (_str){delete[] _str;_str = nullptr;}}
private:char* _str;
};int main()
{String s1("hello world!");String s2(s1);    // 這里會析構兩次,導致程序崩潰return 0;
}

說明:

????????上述String類沒有顯式定義其拷貝構造函數與賦值運算符重載,此時編譯器會合成默認的,當用s1構造s2時,編譯器會調用默認的拷貝構造。最終導致的問題是,s1、s2共用同一塊內存空間,在釋放時同一塊空間被釋放多次而引起程序崩潰,這種拷貝方式,稱為淺拷貝

淺拷貝:

????????也稱位拷貝編譯器只是將對象中的值拷貝過來。如果對象中管理資源,最后就會導致多個對象共享同一份資源,當一個對象銷毀時就會將該資源釋放掉,而此時另一些對象不知道該資源已經被釋放,以為還有效,所以當繼續對資源進項操作時,就會發生發生了訪問違規

????????可以采用深拷貝解決淺拷貝問題,即:每個對象都有一份獨立的資源,不要和其他對象共享。

2.深拷貝

????????如果一個類中涉及到資源的管理,其拷貝構造函數、賦值運算符重載以及析構函數必須要顯式給出。一般情況都是按照深拷貝方式提供。

2.1?傳統寫法的String類

class String
{
public :String(const char* str = ""){if (nullptr == str){assert(false);return;} _str = new char[strlen(str) + 1];strcpy(_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* pStr = new char[strlen(s._str) + 1];strcpy(pStr, s._str);delete[] _str;_str = pStr;} return* this;} ~String(){if (_str){delete[] _str;_str = nullptr;}}private:char* _str;
};

2.1?現代寫法的String類

class String
{
public :String(const char* str = ""){// 構造String類對象時,如果傳遞nullptr指針,可以認為程序非if (nullptr == str){assert(false);return;} _str = new char[strlen(str) + 1];strcpy(_str, str);} String(const String& s): _str(new char[strlen(s._str) + 1]){strcpy(_str, s._str);} // 現代版本String & operator=(String s){std::swap(_str, s._str);return *this;}傳統版本//String& operator=(const String& s)//{//	if (this != &s)//	{//		char* pStr = new char[strlen(s._str) + 1];//		strcpy(pStr, s._str);//		delete[] _str;//		_str = pStr;//	} //	return* this;//} ~String(){if (_str){delete[] _str;_str = nullptr;}}private:char* _str;
};

3.string類的模擬實現

頭文件 string.h:

namespace room
{class string{public:// 迭代器typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}/*string():_str(new char[1]{'\0'}),_size(0),_capacity(0){}*/void swap(string& s);string(size_t n, char ch);string(const char* str = "");// s2(s1)string(const string& s);// s1 = s2// s1 = s1//string& operator=(const string& s);// s1 = s2string& operator=(string s);~string();void clear(){_str[0] = '\0';_size = 0;}const char* c_str() const{return _str;}void reserve(size_t n);void push_back(char ch);void append(const char* str);string& operator+=(char ch);string& operator+=(const char* str);void insert(size_t pos, size_t n, char ch);void insert(size_t pos, const char* ch);void erase(size_t pos = 0, size_t len = npos);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);size_t size() const{return _size;}size_t capacity() const{return _size;}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& operator[](size_t pos) const{assert(pos < _size);return _str[pos];}string substr(size_t pos, size_t len = npos);bool operator==(const string& s) const;bool operator!=(const string& s) const;bool operator<(const string& s) const;bool operator<=(const string& s) const;bool operator>(const string& s) const;bool operator>=(const string& s) const;private:// 聲明char* _str = nullptr;size_t _size = 0;size_t _capacity = 0;const static size_t npos;};ostream& operator<<(ostream& out, const string& s);istream& operator>>(istream& in, string& s);istream& getline(istream& in, string& s, char delim);
}

源文件string.cpp:

// 鏈接時會合并
namespace room 
{const size_t string::npos = -1;string::string(size_t n, char ch):_str(new char[n + 1]),_size(n),_capacity(n){for (size_t i = 0; i < n; ++i){_str[i] = ch;}_str[_size] = '\0';}string::string(const char* str):_size(strlen(str)){_capacity = _size;_str = new char[_size + 1];strcpy(_str, str);}傳統寫法s2(s1)//string::string(const string& s)//{//	_str = new char[s._capacity + 1];//	strcpy(_str, s._str);//	_size = s._size;//	_capacity = s._capacity;//}void string::swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}// 現代寫法// s2(s1)string::string(const string& s){string tmp(s._str);swap(tmp);}// s1 = s2// s1 = s1/*string& string::operator=(const string& s){if (this != &s){delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;}*/// s1 = s2string& string::operator=(string s){swap(s);return *this;}string::~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}void string::reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void string::push_back(char ch){if (_size + 1 > _capacity){// 擴容reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;++_size;_str[_size] = '\0';	// 末尾得加上一個\0}void string::append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){// 擴容size_t newCapacity = 2 * _capacity;if(_size + len > 2 * _capacity){newCapacity = _size + len;}reserve(newCapacity);}strcpy(_str + _size, str);_size += len;}string& string::operator+=(char ch){push_back(ch);return *this;}string& string::operator+=(const char* str){append(str);return *this;}void string::insert(size_t pos, size_t n, char ch){assert(pos <= _size);assert(n > 0);if (_size + n > _capacity){// 擴容size_t newCapacity = 2 * _capacity;if (_size + n > 2 * _capacity){newCapacity = _size + n;}reserve(newCapacity);}// 挪動數據// 這樣挪動數據,頭插的時候會越界/*size_t end = _size;while (end >= pos){_str[end + n] = _str[end];--end;}*/size_t end = _size + n;while (end > pos + n - 1){_str[end] = _str[end - n];--end;}for (size_t i = 0; i < n; ++i){_str[pos + i] = ch;}_size += n;/*string tmp(n, ch);insert(pos, tmp.c_str());*/}void string::insert(size_t pos, const char* str){assert(pos <= _size);size_t n = strlen(str);if (_size + n > _capacity){// 擴容size_t newCapacity = 2 * _capacity;if (_size + n > 2 * _capacity){newCapacity = _size + n;}reserve(newCapacity);}size_t end = _size + n;while (end > pos + n - 1){_str[end] = _str[end - n];--end;}for (size_t i = 0; i < n; ++i){_str[pos + i] = str[i];}}void string::erase(size_t pos, size_t len){if (len >= _size - pos){// 刪完數據_str[pos] = '\0';_size = pos;}else{size_t end = pos + len;while (end <= _size){_str[end - len] = _str[end];++end;}_size -= len;}}size_t string::find(char ch, size_t pos){for (size_t i = pos; i < _size; ++i){if (_str[i] == ch){return i;}}return npos;}size_t string::find(const char* str, size_t pos){const char* p = strstr(_str + pos, str);if (p == nullptr){return npos;}else{return p - _str;}}string string::substr(size_t pos, size_t len){size_t leftlen = _size - pos;// 給的長度大于剩余的長度時,len等于剩余長度if (len > leftlen)len = leftlen;string tmp;tmp.reserve(len);for (size_t i = 0; i < len; ++i){tmp += _str[pos + i];}return tmp;}bool string::operator==(const string& s) const{return strcmp(_str, s._str) == 0;}bool string::operator!=(const string& s) const{return !(*this == s);}bool string::operator<(const string& s) const{return strcmp(_str, s._str) < 0;}bool string::operator<=(const string& s) const{return *this < s || *this == s;}bool string::operator>(const string& s) const{return !(*this <= s);}bool string::operator>=(const string& s) const{return !(*this < s);}ostream& operator<<(ostream& out, const string& s){for (auto ch : s)out << ch;return out;}istream& operator>>(istream& in, string& s){s.clear();// 輸入短串,不會浪費空間// 輸入長串,避免不斷擴容const size_t N = 1024;char buff[N];int i = 0;//cin >> i;	// 這樣是不行的char ch = in.get();	// 用get()才能收到空格和換行// 短串就放入buffwhile (ch != ' ' && ch != '\n')	// 遇到\n就結束{buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if (i > 0){// 長串才擴容,減小擴容帶來的性能消耗buff[i] = '\0';s += buff;}return in;}istream& getline(istream& in, string& s, char delim){s.clear();// 輸入短串,不會浪費空間// 輸入長串,避免不斷擴容const size_t N = 1024;char buff[N];int i = 0;//cin >> i;	// 這樣是不行的char ch = in.get();	// 用get()才能收到空格和換行// 短串就放入buffwhile (ch != delim)	// 遇到指定字符delim就結束{buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if (i > 0){// 長串才擴容,減小擴容帶來的性能消耗buff[i] = '\0';s += buff;}return in;}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/72894.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/72894.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/72894.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用 vxe-table 導出 excel,支持帶數值、貨幣、圖片等帶格式導出

使用 vxe-table 導出 excel&#xff0c;支持帶數值、貨幣、圖片等帶格式導出&#xff0c;通過官方自動的導出插件 plugin-export-xlsx 實現導出功能 查看官網&#xff1a;https://vxetable.cn gitbub&#xff1a;https://github.com/x-extends/vxe-table gitee&#xff1a;htt…

JavaScript數據類型和內存空間

一、JavaScript 數據類型 基本數據類型&#xff1a;字符串&#xff08;String&#xff09;、數字(Number)、布爾(Boolean)、空&#xff08;Null&#xff09;、未定義&#xff08;Undefined&#xff09;、Symbol 引用數據類型&#xff1a;對象(Object)、數組(Array)、函數(Fun…

DNS Beaconing

“DNS Beaconing” 是一種隱蔽的網絡通信技術&#xff0c;通常與惡意軟件&#xff08;如木馬、僵尸網絡&#xff09;相關。攻擊者通過定期發送 DNS請求 到受控的域名服務器&#xff08;C&C服務器&#xff09;&#xff0c;實現與惡意軟件的隱蔽通信、數據傳輸或指令下發。由…

python中采用opencv作常規的圖片處理的方法~~~

在python中&#xff0c;我們經常會需要對圖片做灰度/二值化/模糊等處理&#xff0c;這時候opencv就是我們的好幫手了&#xff0c;下面我來介紹一下相關用法: 首先&#xff0c;需要安裝opencv-python庫: 然后&#xff0c;在你的代碼中引用: import cv2 最后就是代碼了&#x…

CmBacktrace的學習跟移植思路

學習移植CmBacktrace需要從理解其核心功能、適用場景及移植步驟入手&#xff0c;結合理論學習和實踐操作。以下是具體的學習思路與移植思路&#xff1a; 一、學習思路 理解CmBacktrace的核心功能 CmBacktrace是針對ARM Cortex-M系列MCU的錯誤追蹤庫&#xff0c;支持自動診斷Har…

支付寶當面付java,php,sdk下載

SDK & Demo 獲取 - 支付寶文檔中心 開放平臺服務端 SDK 為了幫助開發者調用開放接口&#xff0c;支付寶提供了開放平臺服務端 SDK&#xff0c;包含 Java、PHP、NodeJS、Python 和 .NET 等語言版本&#xff0c;DEMO 中封裝了簽名 & 驗簽、HTTP 接口請求等基礎功能。 詳…

Cocos Creator Shader入門實戰(三):CCEffect參數配置講解

引擎版本&#xff1a;3.8.5 您好&#xff0c;我是鶴九日&#xff01; 回顧 稍微回顧下前面兩篇博客講解的內容&#xff1a; 一、Cocos渲染效果的實現需要Material材質和Effect資源的互相配合。 二、Effect資源負責Shader片段的編寫和屬性配置&#xff0c;Material材質負責對E…

AI日報 - 2025年3月10日

AI日報 - 2025年3月10日 &#x1f31f; 今日概覽&#xff08;60秒速覽&#xff09; ▎&#x1f916; AGI突破 | Anthropic CEO預測強AI最早2026年到來 &#x1f52c; SAGE框架提升問答質量61.25%&#xff0c;Reflexion框架將GPT-4成功率提至91% ▎&#x1f4bc; 商業動向 | xA…

【SegRNN 源碼理解】【今天不水文系列】編碼器部分理解

我來小小的理解一下&#xff1a; 首先&#xff0c;16 batchsize&#xff0c;60sequendcelength&#xff0c;7 個特征的通俗解釋 16 個獨立的樣本&#xff0c;每個樣本有 60 個連續的時間步及對應的標簽值&#xff0c;每個時間步有 60 個特征 所以就是因為樣本是隨機從訓練集…

加速科技Flex10K-L測試機:以硬核創新重塑顯示驅動芯片測試新標桿!

在2024年召開的世界顯示產業創新發展大會上&#xff0c;加速科技自主研發的高密度顯示驅動芯片測試設備Flex10K-L憑借其突破性技術創新&#xff0c;成功入選"十大創新技術&#xff08;產品&#xff09;"。作為國內顯示驅動芯片測試領域的標桿性設備&#xff0c;Flex1…

Docker 部署 Vaultwarden

一、前言 1. 官網 1.1 Vaultwarden https://github.com/dani-garcia/vaultwarden https://github.com/wcjxixi/Vaultwarden-Wiki-Chn https://hub.docker.com/r/vaultwarden/server https://rs.ppgg.in/ # Vaultwarden Wiki 中文版 https://geekdaxue.co/read/Vaultward…

如何下載和使用Git:初學者指南

&#x1f31f; 如何下載和使用Git&#xff1a;初學者指南 在當今的軟件開發中&#xff0c;Git已經成為不可或缺的版本控制系統。無論你是獨立開發者還是團隊成員&#xff0c;掌握Git的基本操作都能幫助你更高效地管理代碼。今天&#xff0c;我將詳細介紹如何下載和使用Git&…

doris: SQL Server

Doris JDBC Catalog 支持通過標準 JDBC 接口連接 SQL Server 數據庫。本文檔介紹如何配置 SQL Server 數據庫連接。 使用須知? 要連接到 SQL Server 數據庫&#xff0c;您需要 SQL Server 2012 或更高版本&#xff0c;或 Azure SQL 數據庫。 SQL Server 數據庫的 JDBC 驅動…

Leetcode 刷題記錄 05 —— 普通數組

本系列為筆者的 Leetcode 刷題記錄&#xff0c;順序為 Hot 100 題官方順序&#xff0c;根據標簽命名&#xff0c;記錄筆者總結的做題思路&#xff0c;附部分代碼解釋和疑問解答。 目錄 01 最大子數組和 方法一&#xff1a;動態規劃&#xff08;卡達尼算法&#xff09; 方法…

《DataWorks 深度洞察:量子機器學習重塑深度學習架構,決勝復雜數據戰場》

在數字化浪潮洶涌澎湃的當下&#xff0c;大數據已然成為推動各行業發展的核心動力。身處這一時代洪流&#xff0c;企業對數據的處理與分析能力&#xff0c;直接關乎其競爭力的高低。阿里巴巴的DataWorks作為大數據領域的扛鼎之作&#xff0c;憑借強大的數據處理與分析能力&…

wordpress自定the_category的輸出結構

通過WordPress的過濾器the_category來自定義輸出內容。方法很簡單&#xff0c;但是很實用。以下是一個示例代碼&#xff1a; function custom_the_category($thelist, $separator , $parents ) {// 獲取當前文章的所有分類$categories get_the_category();if (empty($categ…

2025牛客寒假算法基礎集訓營6

A.復制雞 思路&#xff1a;比較簡單&#xff0c;略。 void solve() {int n, m, k;cin >> n;int last -1, ans 0;for (int i 0; i<n; i){int x;cin >> x;if (x ! last){ans;}last x;}cout << ans << endl; } B.好伙計猜拳 思路&#xff1a;這…

【C#】詳解C#中的內存管理機制

文章目錄 前言一、C#內存管理的基本機制&#xff08;1&#xff09;托管堆&#xff08;Managed Heap&#xff09;&#xff08;2&#xff09;垃圾回收&#xff08;Garbage Collection&#xff09;&#xff08;3&#xff09;棧內存 二、 開發者需要主動管理的場景&#xff08;1&am…

ROS云課基礎題庫-01C++案例-甜甜圈

效率是核心&#xff0c;但效率高的教程會忽略掉非常多的細節。 解決問題的思路和細節對于一個問題的有效求解至關重要。 資料 云課五分鐘-02第一個代碼復現-終端甜甜圈C-CSDN博客 從云課五分鐘到五秒鐘焦慮的甜甜圈向前沖-CSDN博客 說明 復現重要性沒有那么大&#xff0c;…

C/S架構與B/S架構

一、定義與核心區別 C/S架構&#xff08;Client/Server&#xff0c;客戶端/服務器&#xff09; 客戶端需安裝專用軟件&#xff08;如QQ、企業ERP系統&#xff09;&#xff0c;直接與服務器通信。服務器端通常包括數據庫和業務邏輯處理1。特點&#xff1a;客戶端承擔部分計算任務…