C++面試八股文之std::string實現(xiàn)方法
某日二師兄參加XXX科技公司的C++工程師開發(fā)崗位第18面:
面試官:
std::string
用過吧?二師兄:當(dāng)然用過(廢話,C++程序員就沒有沒用過
std::string
的)。面試官:
std::string("hello")+"world"
、"hello"+std::string("world")
和std::string("hello")+std::string("world")
的結(jié)果是什么?為什么?二師兄:前者和后者的結(jié)果都是
std::string
的對象,內(nèi)容是“helloworld\0
”,而中間的這個表達式無法通過編譯。原因是std::string
重載了operator+(const char*)
和operator+(const std::string&)
,但是const char*
卻沒有重載operator+
運算符。面試官:
std::string
有兩個API
,resize
和reserve
,你知道它們之間的區(qū)別嗎?二師兄:
resize
對應(yīng)的是size
,resize
可以改變字符串的大小。reserve
對應(yīng)的是capacity
,reserve
只能改變capacity
的大小。二師兄:當(dāng)
resize
傳入的參數(shù)小于字符串的szie
時,多余的字符串會被截取。當(dāng)reserve
傳入的參數(shù)小于capacity
時,reserve
什么也不會做。二師兄:當(dāng)
resize
傳入的參數(shù)大于字符串的szie
時,增加的字符串會被默認初始化。當(dāng)reserve
傳入的參數(shù)大于capacity
時,capacity
會被擴容。面試官:好的??梢酝ㄟ^下標(biāo)訪問
std::string
實例的內(nèi)容嗎?二師兄:可以的,
std::string
重載了下標(biāo)運算符,可以像數(shù)組一樣通過下標(biāo)運算取出某個字符。面試官:你知道
std::string
的at
成員方法嗎?二師兄: 嗯,和下標(biāo)運算功能相似,不過不用擔(dān)心越界問題??梢园踩脑L問字符串中的字符。
面試官:既然有
at
方法了,為什么還要重載下標(biāo)運算符呢?二師兄:主要是因為性能上的考量。
at
雖然保證了不會超出字符串范圍(超出范圍拋出異常),但是性能低于下標(biāo)操作。這就是有舍有得。為了安全使用at
,為了性能使用下標(biāo)操作。C++給了你多個選擇,如何選擇看你的需求。面試官:那你知道
std::string
是如何實現(xiàn)的嗎?二師兄:在
string
內(nèi)部維護一個指針,這個指針指向真正的字符串的位置。面試官:能簡單的寫一下實現(xiàn)代碼嗎?
二師兄:好的。
class string { public: string():size_(0),data_(nullptr){} explicit string(const char* c) { size_ = strlen(c); data_ = (char*)malloc(size_+1); memset(data_,0,size_+1); memcpy(data_,c,size_); } size_t size() const {return size_;} const char* c_str() const {return data_;} private: size_t size_; char* data_; };
二師兄:在實現(xiàn)
append
或者+=
的時候,需要把當(dāng)前字符的長度加上append
的內(nèi)容的長度,以此長度申請一塊新內(nèi)存,然后把當(dāng)前字符串的內(nèi)存和append
的內(nèi)容考入新申請的內(nèi)存中。free
掉之前data_
指向的內(nèi)存,然后把data_
指針指向新申請的內(nèi)存。面試官:好的。這樣的實現(xiàn)有一些弊端。如果頻繁的對一個
std::string
對象append
內(nèi)容,會發(fā)生什么?二師兄:是的,因為頻繁的
malloc
和free
,會有性能問題。因所以編譯器在實現(xiàn)std::string
的時候一般會預(yù)先申請一塊大的內(nèi)存,這塊內(nèi)存的長度是capacity
,當(dāng)添加的字符串的長度加上當(dāng)前的字符串長度小于capacity
時,直接添加到當(dāng)前的塊上即可。面試官:好的。針對字符串比較少的情況,一般編譯器會做一些優(yōu)化,你知道如何優(yōu)化的嗎?
二師兄:這個好像在哪看過,不記得額。。。
面試官:好的,今天的面試結(jié)束了,請回去等通知吧。
今天二師兄的表現(xiàn)不錯,除了最后一個問題,基本上都答上來了。讓我們來看下這個問題:
針對字符串比較少的情況,一般編譯器會做一些優(yōu)化,你知道如何優(yōu)化的嗎?
我們可以看看GCC中std::string
的實現(xiàn):
typedef basic_string<char> string;
_Alloc_hider _M_dataplus; size_type _M_string_length; enum { _S_local_capacity = 15 / sizeof(_CharT) }; union { _CharT _M_local_buf[_S_local_capacity + 1]; size_type _M_allocated_capacity; };
這里的_CharT
就是char
,所以_S_local_capacity
等于15
。當(dāng)字符串的長度小于等于15
時,直接存在_M_local_buf
中,而不需要在堆中申請內(nèi)存。當(dāng)字符串長度大于15
時,在內(nèi)存中申請一塊內(nèi)存,這塊內(nèi)存的起始地址保存在_M_dataplus
中,這塊內(nèi)存的容量保存在_M_allocated_capacity
中,而字符串的真實長度保存在_M_string_length
中。當(dāng)向字符串中添加字符時,如果添加字符的長度大于 _M_allocated_capacity - _M_string_length
,則需要resize
,否則直接追加到_M_dataplus
保存的內(nèi)存塊中即可。
好了,今天的面試到這里就結(jié)束了。
到此這篇關(guān)于C++面試八股文之std::string實現(xiàn)方法的文章就介紹到這了,更多相關(guān)C++實現(xiàn)std::string內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Linux系統(tǒng)中C語言編程創(chuàng)建函數(shù)fork()執(zhí)行解析
最近在看進程間的通信,看到了fork()函數(shù),雖然以前用過,這次經(jīng)過思考加深了理解?,F(xiàn)總結(jié)如下2013-04-04C++中const、volatile、mutable使用方法小結(jié)
這篇文章主要介紹了C++中const、volatile、mutable使用方法小結(jié),需要的朋友可以參考下2020-01-01利用C++實現(xiàn)通訊錄管理系統(tǒng)的完整代碼
通訊錄是一個可以記錄親人、好友信息的工具,下面這篇文章主要給大家介紹了關(guān)于利用C++實現(xiàn)通訊錄管理系統(tǒng)的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-06-06