中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++ STL主要組件之String總結(第二部分 深、淺拷貝問題以及賦值運算符重載)

發布時間:2020-08-11 14:38:10 來源:網絡 閱讀:278 作者:sonissa 欄目:編程語言

第一部分連接https://blog.51cto.com/14232799/2447326

二.String的模擬實現

在第一步之后緊接著的就該是模擬實現部分,這一部分主要是體現自己對第一部分的掌握情況。強烈推薦和我一樣在學習String的朋友們自己動手實現一下。因為在面試中,面試官總喜歡讓我們自己來模擬實現string類。

自己來實現String最主要是實現String類的構造、拷貝構造、賦值運算符重載(第一部分operator開頭的方法)以及析構函數。

以下是我完成的基礎模擬實現

#include<iostream>
#include<assert.h>
using namespace std;

namespace self{
    class string{
    public:
        string(const char* s = " "){
            if (s == nullptr){
                assert(false);
                return;
            }
            _s = new char[strlen(s) + 1];
            strcpy(_s, s);
        }
        ~string(){
            if (_s){
                delete[] _s;
                _s = nullptr;
            }
        }
    private:
        char* _s;
    };
}
int main(){
    self::string k = "hello";
    self::string i("world");
    self::string m;
    //self::string l(k);
    return 0;
}

以上就是沒有重載賦值運算符且沒有顯式定義拷貝構造函數的string類模擬實現。基本完整的模擬實現會在本篇文章的最后給出(當然免不了有紕漏,若是發現請各位大佬提醒)
上面的代碼中的main函數中有一句注釋語句 //self::string l(k); 我將其注釋是因為如果加入這一句代碼程序就會運行崩潰!!!!
程序崩潰的原因是: 當我們不去顯式定義拷貝構造方法的時候,系統就會生成默認的拷貝構造函數,這種拷貝構造函數是一種淺拷貝,最終結果就是導致 對象l和對象k在共用同一塊內存空。看起來似乎沒什么問題?
但是!當函數結束時,在調用析構函數的操作上就會出現大問題。
原本的話,每一個對象都會調用一次析構函數來清理自己占用的空間。但是當兩個對象所占用的是同一塊空間時,一個對象調用完析構函數后另一個對象調用析構函數的時候,就會生同一塊空間被釋放多次的程序錯誤!從而引起程序崩潰!
所以說在以上這個的代碼中不可以使用拷貝構造方法。這個問題也就引出了下一個要總結的部分:淺拷貝和深拷貝

三.淺拷貝和深拷貝

1.淺拷貝
此處只是給個定義:
淺拷貝:也稱位拷貝,編譯器只是將對象中的值拷貝過來。如果對象中管理資源,最后就會導致多個對象共享同一份資源,當一個對象銷毀時就會將該資源釋放掉,而此時另一些對象不知道該資源已經被釋放,以為還有效,所以 當繼續對資源進項操作時,就會發生發生了訪問違規。所以要解決淺拷貝問C++中引入了深拷貝。
(第二部分的string模擬事先就是個例子)
放個圖片占位:
C++ STL主要組件之String總結(第二部分  深、淺拷貝問題以及賦值運算符重載)
2.深拷貝
“如果一個類中涉及到資源的管理,其拷貝構造函數、賦值運算符重載以及析構函數必須要顯式給出。一般情況都是按照深拷貝方式提供”
上面這句話是真理!
首先給出深拷貝一般在string'類中的實現:

String(const String& s)
 : _str(new char[strlen(s._str)+1])   // 看見這一步開辟空間就知道是深拷貝了
 {
 strcpy(_str, s._str);
 }

再來說深拷貝的定義:
每個string都需要空間來存放字符串,而當使用一個string類對象來構造另一個string類對象。就用到了深拷貝:給每個對象獨立分配資源,保證多個對象之間不會因共享資源而造成空間多次釋放而造成的程序奔潰問題。

三.String中賦值運算符重載
1.先給出幾種在string中常用的賦值運算符重載:
<1> <<

ostream& bit::operator<<(ostream& _cout, const self::String& s)
{
 cout << s._str;
 return _cout;
}

對于<<的重載算是比較特殊的了,因為會用到ostream類型,所以在這里展開說明一下:
ostream是output stream的簡稱,即輸出流。一個典型的輸出流對象就是在C++中標準輸出流cout。
在C++中,很少自定義ostream的對象,更多的是直接使用cout。
ostream這個類型,往往出現在<<操作重載中,作為某個類的友元函數出現。
比如對于class A, 可以定義ostream & operator << (ostream &os, const A& a);
這樣在調用A的對象var時,就可以這樣使用
cout &lt;&lt; var ;

<2> =

String& operator=(String s)
 {
 swap(_str, s._str); 
 return *this;
 }

<3> +=

string& operator+=(char ch)
        {
            push_back(ch);
            return *this;
        }

<4> [ ]

char& operator[](size_t index)
 {
 assert(index < _size);
 return _str[index];
 }

四.最后是給出的較為完整的string類模擬實現:

namespace key
{
 class String
 {
 public:
 typedef char* iterator;
 public:
 String(const char* str = "")
 {
 _size = strlen(str);
 _capacity = _size;
 _str = new char[_capacity+1];
 strcpy(_str, str);
 }
 String(const String& s)
 : _str(nullptr)
 , _size(0)
 , _capacity(0)
 {
 String tmp(s);
 this->Swap(tmp);
 }
 String& operator=(String s)
 {
 this->Swap(s)
 return *this;
 }
 ~String()
 {
 if (_str)
 {
 delete[] _str;
 _str = nullptr;
 }
 }
 /////////////////////////////////////////////////////////////////
 // iterator
 iterator begin() {return _str;}
 iterator end(){return _str + _size;}
 /////////////////////////////////////////////////////////////////
 // modify
 void PushBack(char c)
 {
 if (_size == _capacity)
 Reserve(_capacity*2);

 _str[_size++] = c;
 _str[_size] = '\0';
 }
 String& operator+=(char c)
 {
 PushBack(c);
 return *this;
 }
 void Clear()
 {
 _size = 0;
 _str[_size] = '\0';
 }
 void Swap(String& s)
 {
 swap(_str, s._str);
 swap(_size, s._size);
 swap(_capacity, s._capacity);
 }
 const char* C_Str()const
 {
 return _str;
 }
 size_t Size()const
 size_t Capacity()const
 bool Empty()const

 void Resize(size_t newSize, char c = '\0')
 {
 if (newSize > _size)
 {
 // 如果newSize大于底層空間大小,則需要重新開辟空間
 if (newSize > _capacity)
 {
 Reserve(newSize);
 }
 memset(_str + _size, c, newSize - _size);
 }
 _size = newSize;
 _str[newSize] = '\0';
 }
 void Reserve(size_t newCapacity)
 {
 // 如果新容量大于舊容量,則開辟空間
比特科技
 if (newCapacity > _capacity)
 {
 char* str = new char[newCapacity + 1];
 strcpy(str, _str);
 // 釋放原來舊空間,然后使用新空間
 delete[] _str;
 _str = str;
 _capacity = newCapacity;
 }
 }
 char& operator[](size_t index)
 {
 assert(index < _size);
 return _str[index];
 }
 const char& operator[](size_t index)const
 {
 assert(index < _size);
 return _str[index];
 }
 private:
 friend ostream& operator<<(ostream& _cout, const bit::String& s);
 private:
 char* _str;
 size_t _capacity;
 size_t _size;
 };
}
ostream& key::operator<<(ostream& _cout, const bit::String& s)
{
 cout << s._str;
 return _cout;
}
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

金山区| 闸北区| 资源县| 东方市| 湖口县| 兴仁县| 梁山县| 余姚市| 额济纳旗| 日照市| 万荣县| 黄骅市| 沧源| 保山市| 永定县| 山阳县| 陆川县| 东丽区| 蕲春县| 墨玉县| 扬中市| 建水县| 琼中| 忻州市| 天台县| 平远县| 安康市| 夏河县| 孝义市| 长治县| 怀仁县| 隆林| 嵩明县| 尼玛县| 石城县| 曲阜市| 平乐县| 来安县| 化德县| 兴义市| 黎城县|