使用QStringBuilder進行字串連線

2022-06-19 21:42:14 字數 4095 閱讀 4772

** 

in c++

performance

qtqt-labs-chinese | comments

qstring和qbytearray提供了非常便利的operator+,以允許你寫這樣的**:

qstring directory = /*...*/, name = /*...*/;

qstring datafile = directory + qlatin1char('/') + name + qlatin1string(".dat");

非常方便。

qlatin1charqlatin1string用在這兒只是出於正確性的考慮,你在編寫自己的應用程式時可以省略它們。

雖然我們有了很方便的東西,但是這種表示式的效能如何呢?

每個operator+都會建立乙個乙個臨時字串,然後將其丟棄,這意味著,會有很多次的記憶體分配和拷貝。

如果(像下面)這樣做的話,將會快很多。

qstring datafile = directory;

datafile.reserve(directory.size() + 1 + name.size() + 4);

datafile += qlatin1char('/');

datafile += name;

datafile += qlatin1string(".dat");

只需要一次記憶體分配和拷貝,這是最優的結果。但不幸的是,看起來不是那麼好。

倘若第乙個表示式和上面這個一樣快會怎麼樣?好訊息是——這是可能實現的。

在qt 4.6中我們引入乙個隱藏的類:qstringbuilder。

在4.8中我們新增了對qbytearray的支援。

由於這是原始碼不相容的(見下文),你需要顯式地啟用它。

在qt 4.7中啟用它的方法在4.7 qstring文件中有介紹。

但是這種方法現在被廢棄了,而且在qt 4.8中,這個巨集已被新的qt_use_qstringbuilder巨集所替代。要想受益於qbytearray的改變,你必須使用新的巨集。

為了使其工作,我們使用了乙個被稱為表示式模板(expression template)的技術。

我們修改了一些接受字串的operator+,使其返回乙個特殊的模板類,它的結果將會延遲(lazily)計算。

舉例來說,當定義qt_use_qstringbuilder後,string1 + string2的型別將是可以隱式轉換成qstring的qstringbuilder

這是原始碼不相容的,因為你可能寫有假定operator+的返回值是qsting型別的**。

qvariant v = somestring + someotherstring;

qstring s = (somestring + someotherstring).toupper();

解決方案是顯式轉換成qstring:

qvariant v = qstring(somestring + someotherstring);

qstring s = qstring(somestring + someotherstring).toupper();

編譯qt自身和qt creator時,qt_use_qstringbuilder已經被啟用了。

一些修復原始碼相容性問題的提交(commit)有:

5d3eb7a1對於尚未支援qbytearray的早期版本,和7101a3fa在qt 4.8中新增對qbytearray支援。

技術細節

考慮到本實現展示了許多很好的模板特性,我認為在本文中解釋一點這個類的細節將會非常有趣。它是高度技術性的,但使用它的話卻完全不要求你理解這些。

一切均在qtringbuilder.h中,為了便於理解本文中的貼出的**片段可能稍微做了一點簡化。

讓我們從operator+的實現開始看起:

template 

qstringbuilder::type, typename qconcatenable::type>

operator+(const a &a, const b &b)

該操作符使用sfinae來做到僅對支援字串連線的型別起作用。實際上,qcontatenable是乙個只對qstring、qlatin1string、qchar、qstringref、qcharref以及qbytearray和char*進行了特化的內部模板類。

qconcatenable::type是型別t的別名(typedef),且只對這些特殊的型別有效。

比如,由於qconcatenable::type不存在,operator+用於qvariant時將不會被啟用。

operator+(a,b)簡單地返回qstringbuilder(a, b);

像這樣的一些東西string1 + string2 + string3,其結果的型別將是qstringbuilder< qstringbuilder , qstring>

現在我們可以看一下qstringbuilder類

template 

class qstringbuilder

template t convertto() const;

typedef typename qconcatenable>

::convertto convertto;

operator convertto() const

};依賴於型別a和b,別名convertto將代表qbytearray或qstring,稍後我們會看到這是如何做到的。因此qstringbuilder只儲存它的運算元的引用。

當qstringbuilder隱式地被轉換成qstring或qbytearray時,函式convertto()將被呼叫:

舉例來說,對於qstring,這是qconcatenable看起來的樣子

我們如何才能知道我們需要轉換成qstring還是qbytearray?讓我們來嘗試理解一下convertto型別是如何確定的:

namespace qtstringbuilder ;

template struct converttotypehelper

;}

converttotypehelper被用來計算qconcatenable< qstringbuilder>::convertto。它是乙個模板計算(template computation)。它可以被看作是接收兩個型別引數(c和d)並以別名converttotypehelper::convertto的型別返回的函式。

預設情況下,convertto總是第乙個型別。但如果第二個型別是qstring,模板偏特化將被使用,而qstring將被「返回」。

在實際中,這意味著只要任何乙個型別是qstring,qstring就將被返回。

為可感知unicode的型別(qstring、qlatin1string、qchar、...)特化的qconcatenable將qstring取為convertto,而其他基於8位字元的型別將convertto

作為qbytearray的別名。

現在讓我們看一下關於qbytearray的特化:

與qstring相同,但是qt允許你隱式地將qbytearray轉換為qstring,這也是為什麼這裡有乙個從ascii到unicode轉換的過載。通過定義qt_no_cast_from_ascii可以禁用它。由於你不知道應用程式的開發者在他的**中會使用何種編碼,在庫**中只使用顯式轉換(通過qlatin1string)是乙個好的實踐。

結論我跳過了一些細節,比如對一些像utf-8的編碼可能有不同的大小(查閱**中的exactsize)這些事實的支援。

(順便一提,如果你聽過說qlatin1literal,不要怕使用它。對字串常量,編譯器內建的strlen將在編譯時被計算)

***************== end

使用GraphEdit使用

1 註冊元件。其實乙個filter就是乙個com元件,所以使用之前需要註冊,可以有兩種方法對元件進行註冊。1.直接使用命令。命令列下輸入 regsvr32 hqtlystd.ax 編譯之後你會在工程目錄下的debug中找到hqtlystd.ax,這個就是要用的filter 即可註冊成功。2.vc6....

MySQL使用學習使用 mysql學習使用

1 mysql學習 1 安裝 ubuntu下直接安裝 apt get install mysql server 2 檢查伺服器是否啟動 sudo netstat tap grep mysql,如果啟動成功,出現以下資訊 tcp00localhost.localdomain mysql listen ...

學習使用CSDN markdown使用

建立乙個自定義列表 如何建立乙個註腳 注釋也是必不可少的 katex數學公式 新的甘特圖功能,豐富你的文章 uml 圖表 flowchart流程圖 匯出與匯入 你好!這是你第一次使用markdown編輯器所展示的歡迎頁。如果你想學習如何使用markdown編輯器,可以仔細閱讀這篇文章,了解一下mar...