std string原始碼剖析 1 體系結構

2021-10-02 02:58:23 字數 4437 閱讀 2010

一直以來廣大c++使用者對標準庫中std::string褒貶不一,筆者整理了一下,大致是以下幾點

不支援一些常用功能,例如format

有algorithm的情況下.basic_string支援的功能太多,過於冗餘,

缺少編碼資訊,對於寬位元組等有其它的容器,比如wstring,u16string,u32string.

不少地方效率不夠

比起字串更應該叫位元組串,它並不像其他語言一樣唯讀的(string_view).…

種種原因使得我的內心充滿了疑惑,所以決定欣賞下庫的**,我們開始吧

我們首先來看看string到底是什麼

template

<

class

_chart

>

struct char_traits;

template

<

>

struct char_traits<

char

>

;#ifdef _glibcxx_use_wchar_t

template

<

>

struct char_traits<

wchar_t

>

;#endif

#if ((__cplusplus >= 201103l) \

&& defined(_glibcxx_use_c99_stdint_tr1))

template

<

>

struct char_traits<

char16_t

>

;template

<

>

struct char_traits<

char32_t

>

;#endif

_glibcxx_begin_namespace_cxx11

template

<

typename _chart,

typename _traits = char_traits<_chart>

,typename _alloc = allocator<_chart>

>

class

basic_string

;/// a string of @c char

typedef basic_string<

char

> string;

#ifdef _glibcxx_use_wchar_t

/// a string of @c wchar_t

typedef basic_string<

wchar_t

> wstring;

#endif

#if ((__cplusplus >= 201103l) \

&& defined(_glibcxx_use_c99_stdint_tr1))

/// a string of @c char16_t

typedef basic_string<

char16_t

> u16string;

/// a string of @c char32_t

typedef basic_string<

char32_t

> u32string;

#endif

我們終於看到了string的真面目,其實string不是乙個單獨的類 它只不過是basic_string這個模板的乙個例項而已,

我們再來看看basic_string是什麼

template

<

typename _chart,

typename _traits,

typename _alloc>

class

basic_string

我們可以看到basic_string模板有三個引數 乙個是前面提到的型別,乙個是traits,乙個是alloc

我們乙個乙個來說 首先說說traits,我們可以看到在上面的第一欄**中給traits的型別的char_traits,那麼這究竟是什麼呢,我們來看看char_traits的宣告

template

<

typename _chart>

struct char_traits

我們看到其實就是一些型別的宣告 剩下的函式就是一些簡單的字元操作

我們再來看看char_traits< char>

template

<

>

struct char_traits<

char

>

static _glibcxx_constexpr booleq(

const char_type& __c1,

const char_type& __c2) _glibcxx_noexcept

....

.}

其實char型別就是乙個全特化 其實不僅是char型別的有特化 char16_t,char32_t等也都有 至於為什麼要給不同的型別有特化 原因就是比較中的memcmp函式使用了不同的版本.

到這裡我們算是清楚了三個模板引數中乙個的含義,就是char_traits,其作用就是對簡單的低階字串操作進行封裝

其實剩下的引數就不必多說,乙個是必要的型別,乙個是alloctor.

我們來細細看看basic_string的內部資料

template

<

typename _chart,

typename _traits,

typename _alloc>

class

basic_string

#else

_alloc_hider

(pointer __dat,

const _alloc& __a)

:allocator_type

(__a)

,_m_p

(__dat)

_alloc_hider

(pointer __dat, _alloc&& __a =

_alloc()

):allocator_type

(std::

move

(__a)),

_m_p

(__dat)

#endif

pointer _m_p;

// the actual data.};

_alloc_hider _m_dataplus;

size_type _m_string_length;

enum

;union..

....

};

其實自npos 前面的型別宣告簡單的了解的話大可不必深究,因為其應用都是有場景的,用的時候自會出現,沒有必有把這個過程反過來去學習,

首先我們看第乙個資料_m_dataplus這個其實就是乙個資料的封裝,把alloctor和string的源資料存放在一起,方便管理,在c++11後支援了右值,

第二個引數就是_m_string_length這個也很好理解,就是當前資料的有效長度,因為指標是從alloctor分配來的,資料不一定會把所有的資料域佔滿

第三個引數就比較有意思了_s_local_capacity本地容量? 奇怪的名字,我們的資料不都是從alloctor中來的嗎,為什麼會出現乙個本地容量, 這就是string的核心之一 就是短字串優化,我們可以看看下乙個資料,乙個聯合體,其中有乙個引數我們要多加注意,_m_local_buf[_s_local_capacity + 1],奇怪,為什麼string中會有乙個靜態陣列呢,其實這就是短字串優化,當string中的資料較小時,把資料儲存在靜態陣列中,alloctor就不必進行一次記憶體分配,從而減少一次系統呼叫,減少一次使用者態向核心態的轉換,這就是短字串優化,

最後再來看看_m_allocated_capacity這個引數,其含義就是容量,也就是分配的記憶體大小,很巧妙的設計,當使用靜態記憶體的時候,容量為15,不用計算,當大於15的時候靜態陣列便沒有用了,正好用來記錄容量,至於如何區分使用的記憶體是靜態的還是由alloctor分配的,就是我們的_m_dataplus要做的事了,其中有乙個指標,指向資料,我們只需要在進行短字串優化時把指標指向靜態陣列即可

以上就是string的體系結構部分

原始碼剖析 Hashtable 原始碼剖析

hashtable同樣是基於雜湊表實現的,同樣每個元素都是key value對,其內部也是通過單鏈表解決衝突問題,容量不足 超過了閾值 時,同樣會自動增長。hashtable也是jdk1.0引入的類,是執行緒安全的,能用於多執行緒環境中。hashtable同樣實現了serializable介面,它支...

《STL原始碼剖析》筆記 1

第一章 stl概論與版本簡介 一 臨時物件的產生與運用。p36 這裡的臨時物件,指的是一種無名物件 unnamed subjects 如果它們的產生不在程式設計師的預料之下,往往造成效率的負擔,但有時刻意製造臨時物件會讓程式乾淨清爽。刻意製造臨時物件的方法是,在型別名稱後直接加一對小括號,並可指定初...

nginx原始碼剖析 1 概要

用 剖析 這個詞語有點大言不慚了。一直對伺服器程式設計感興趣,選擇nginx作為分析的物件是因為其效率比較高,量也比較合適 10w行左右 質量高,作者對效率要求非常高,對 也有異乎尋常的潔癖。打算寫成乙個系列,但是本人文件水平一直偏弱,而且寫在這裡主要目的也只是為了當作學習筆記記錄,所以如果各位看官...