**
in c++
performance
qtqt-labs-chinese | comments
qstring和qbytearray提供了非常便利的operator+
,以允許你寫這樣的**:
qstring directory = /*...*/, name = /*...*/;非常方便。qstring datafile = directory + qlatin1char('/') + name + qlatin1string(".dat");
qlatin1char
和qlatin1string
用在這兒只是出於正確性的考慮,你在編寫自己的應用程式時可以省略它們。
雖然我們有了很方便的東西,但是這種表示式的效能如何呢?
每個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:qstring s = (somestring + someotherstring).toupper();
qvariant v = qstring(somestring + someotherstring);編譯qt自身和qt creator時,qstring s = qstring(somestring + someotherstring).toupper();
qt_use_qstringbuilder
已經被啟用了。
一些修復原始碼相容性問題的提交(commit)有:
5d3eb7a1對於尚未支援qbytearray的早期版本,和7101a3fa在qt 4.8中新增對qbytearray支援。
技術細節
考慮到本實現展示了許多很好的模板特性,我認為在本文中解釋一點這個類的細節將會非常有趣。它是高度技術性的,但使用它的話卻完全不要求你理解這些。
一切均在qtringbuilder.h中,為了便於理解本文中的貼出的**片段可能稍微做了一點簡化。
讓我們從operator+
的實現開始看起:
template該操作符使用sfinae來做到僅對支援字串連線的型別起作用。實際上,qcontatenable是乙個只對qstring、qlatin1string、qchar、qstringref、qcharref以及qbytearray和char*進行了特化的內部模板類。qstringbuilder::type, typename qconcatenable::type>
operator+(const a &a, const b &b)
qconcatenable::type是型別t的別名(typedef),且只對這些特殊的型別有效。
比如,由於qconcatenable::type不存在,operator+
用於qvariant時將不會被啟用。
operator+(a,b)
簡單地返回qstringbuilder(a, b);
。
像這樣的一些東西string1 + string2 + string3
,其結果的型別將是qstringbuilder< qstringbuilder , qstring>
現在我們可以看一下qstringbuilder類
templateconverttotypehelper被用來計算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
;}
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...