QT字符串高效拼接原理QStringBuilder
這一篇文章討論QT框架中QT字符串是如何實現高效拼接的。
1. QStringBuilder實例與原理
QT字符串高效拼接例子
備註:
(a)上述代碼僅僅在s2 = b1時一次性分配能夠容納所有字符串的內存。
(b)定義兩個符號之一即可使用operator+實現高效字符串拼接。
QT_USE_FAST_OPERATOR_PLUS
QT_USE_QSTRINGBUILDER
QStringBuilder原理
QStringBuilder提升字符串拼接性能的原理是什麼?
(1)QStringBuilder是一個模板, QStringBuilder<A, B>。
(2)內部僅僅保存了構造時傳入的各種類型的字符串的引用。
(3)模板參數又可以嵌套一個QStringBuilder。
(4)最後需要獲取拼接結果時,執行operator QString()類型轉換。
在這個轉換中先計算總的字符串長度,然後一次性分配內存,構造出符合長度要求的QString,最後將各個組成部分拷貝到這個字符串中。
(5)整個拼接過程只需要分配一次內存,構造一個QString字符串作為最終拼接結果。中間不構造任何臨時字符串。
2. 自己實現字符串高效拼接
目標
備註:
(a)重載operator%運算符時必須至少有一個參數是類類型或者枚舉類型。
因此不能直接實現兩個原始字符串的%運算。
可連接類型
備註:
(a)這個類型關注具體如何進行連接操作,以及連接之後應該有多大。
為什麼這個類型看起來並沒有任何關於如何進行連接操作以及連接之後應該有多大的函數或者屬性定義呢?這個是默認通用版本,通用版本無法確定數據類型,當然也就無法確定這些關注點,針對具體類型的特化版本才能確定這些關注點。
類型選擇類型
備註:
(a)這個類型關注兩個類型連接之後的結果類型是什麼類型。
字符串拼接類型
備註:
(a)這個類型相當於字符串連接的一個總控程序。
特化版本: ButianyunStringBuilder
思考:
問題:類模板的特化版本中的模板參數是否可以比通用版本的模板參數更多呢?
答案:顯然是可以的。ButianyunConcatenable就是這麼一個具體的實例。
思考
問題:
根據ButianyunConvertHelper的定義,A和B連接後的新類型為A。
為什麼不直接在這裡定義A為ConvertToType,而是搞出來ButianyunConvertHelper這個模板呢?
答案:
ButianyunConvertHelper的價值是什麼? 核心價值在於特化版本可以根據A和B的具體情況來定義A和B哪一個類型作為新類型。 在ButianyunConcatenable中無需關注這個問題。 如果不定義這個模板,直接定義A為ConvertToType則為硬編碼。
將A和B連接後的新類型的決定權較給了這個類型外部的ButianyunConvertHelper。
ButianyunConcatenable關注如何連接這件事情本身,而ButianyunConvertHelper關注類型。 優點是簡化了ButianyunConcatenable的代碼。 因此本質是關注點分離的思想。
特化版本:QLatin1String
特化版本: 原始字符數組
字符串連接函數
運算符重載:operator%
備註:
(a)這個運算符重載相當於對外提供了一個簡化版本的API接口。
3. 總結
如果自己按照QT框架中QStringBuilder原理實現了字符串高效拼接則對QStringBuilder就有了更深入的認識了,對一個概念和用法做到知其然知其所以然。本文前面介紹的ButianyunStringBuilder實現基本上是QT框架中QStringBuilder的源碼實現的簡化版本。理解了ButianyunStringBuilder源代碼基本上就已經掌握了QStringBuilder的源代碼。
這個代碼中使用了一些C++模板編程技術。C++模板編程技術本質上是一種取捨權衡之道,使用編譯時間換取運行時間,也就是代碼編譯時間可能多一點,程序運行時的性能可能高一點。QT框架源代碼很多時候為了追求運行時期的性能而使用了C++模板編程技術,使得源代碼看起來有一點晦澀難懂。因此必須熟練掌握C++模板編程技術才能更好的掌握QT框架源代碼。對於QT框架為什麼使用這種模板編程技術,個人理解可能是這樣的:QT框架的最大的特點在於易用性,但是QT框架中的很多基礎設施又不想損失運行時期性能,那麼自然而然就使用C++模板編程技術;當然有得必有失,損失一點源代碼的可讀性也可以算是提升了一點閱讀源代碼的門檻也就是很正常的事情;另外對於熟練掌握C++模板編程技術的軟件工程師而言可能也不算什麼門檻。
如果想更好的掌握C++,可以多看一些優秀的大型框架的源代碼。這些大型框架經過多年沉澱,往往有一些比較優秀的編程思想。個人理解,掌握一些最基本最本質的編程思想可能比掌握一些框架的模擬兩可的概念或者一些表面的API用法更實在一些,收益也更大一些。這也是在探索和分析QT源代碼的過程中產生的一點可能在一些大佬看起來可能不值得一提的一點個人想法。