目錄
- Qt中的字串
- QLatinString
- 詳細介紹
- 原始碼
- 小結
- QStringLiteral(str)
- 詳細介紹
- 原始碼
- 小結
- QLatinString
Qt中的字串
Qt中處理字串最常用的肯定是QString,但是在qt creator原始碼中出現了大量的QLatin1String,下面我們來介紹下區別,
QLatinString
詳細介紹
我們首先來看QLatinString,類詳細介紹如下:
QString的許多成員函式都被多載以接受const char *而不是QString, 這包括復制建構式,賦值運算子,比較運算子以及各種其他函式,例如insert(),replace()和indexOf(), 這些函式通常經過優化,以避免為const char *資料構造QString物件, 例如,假設str是QString,
QLatin1String類為US-ASCII/Latin-1編碼的字串文字提供了一個小型包裝器,
QString的許多成員函式都被多載以接受const char *引數而不是QString引數, 這包括復制建構式,賦值運算子,比較運算子以及各種其他函式,例如insert(),replace()和indexOf(), 這些函式通常經過優化,以避免為const char *資料構造QString物件, 例如,假設str是QString,
if (str == "auto" || str == "extern"
|| str == "static" || str == "register") {
...
}
比下面的快很多
if (str == QString("auto") || str == QString("extern")
|| str == QString("static") || str == QString("register")) {
...
}
因為它不會構造四個臨時QString物件并進行字符資料的深拷貝,
定義QT_NO_CAST_FROM_ASCII宏(如QString檔案中所述)的應用程式無法訪問QString的const char * 介面API,為了提供一種指定常量Latin-1字串的有效方法,Qt提供了QLatin1String,它是const char *的非常薄的包裝,使用QLatin1String,上面的示例代碼變為
if (str == QLatin1String("auto")
|| str == QLatin1String("extern")
|| str == QLatin1String("static")
|| str == QLatin1String("register") {
...
}
鍵入的時間稍長一些,但是它提供的功能與代碼的第一個版本完全相同,并且比使用QString::fromLatin1()轉換Latin-1字串的速度更快,
多虧了QString(QLatin1String)建構式,QLatin1String可以在需要QString的任何地方使用, 例如:
QLabel *label = new QLabel(QLatin1String("MOD"), this);
注意:如果你呼叫的函式,使用QLatin1String作為引數,實際上并未被多載來使用QLatin1String,而是進行QString的隱式轉換,并將觸發記憶體分配,而這是你通常使用QLatin1String首先要避免的情況,在這些情況下,使用QStringLiteral可能是更好的選擇,
原始碼
我們看下QLatin1String原始碼,進行了截取,展現核心部分
class QLatin1String
{
public:
inline QLatin1String() : m_size(0), m_data(nullptr) {}
inline explicit QLatin1String(const char *s) : m_size(s ? int(strlen(s)) : 0), m_data(s) {}
private:
int m_size;
const char *m_data;
}
我們可以發現,真的是簡單的包裝,也沒有什么深拷貝什么的,只是把地址簡單的賦給了成員變數m_data,
小結
簡單說,QLatin1String就是對const char*的簡單包裝,用在QT_NO_CAST_FROM_ASCII導致無法訪問QString的const char*介面的地方,
QStringLiteral(str)
QString這個大家都很熟悉了,我們也不過多介紹,這里提一下QStringLiteral,大家可以在QString類介紹中找到,
詳細介紹
這是一個宏,在編譯時從字串文字str中為QString生成資料, 在這種情況下,可以免費創建QString,并且將生成的字串資料存盤在已編譯目標檔案的只讀段中,
如果您的代碼如下所示:
// hasAttribute takes a QString argument
if (node.hasAttribute("http-contents-length")) //...
然后這將創建一個臨時QString作為hasAttribute函式引數進行傳遞, 這可能會非常昂貴,因為它涉及記憶體分配以及將資料復制/轉換為QString的內部編碼,
通過使用QStringLiteral可以避免此成本:
if (node.hasAttribute(QStringLiteral(u"http-contents-length"))) //...
在這種情況下,QString的內部資料將在編譯時生成,在運行時不會發生任何轉換或分配,
使用QStringLiteral而不是用雙引號引起來的純C++字串文字,可以顯著加快根據編譯時已知的資料創建QString實體的速度,
注意:當將字串傳遞給具有多載QLatin1String引數的函式時,QLatin1String仍比QStringLiteral更有效,并且此多載避免了轉換為QString,例如,QString::operator ==()可以直接與QLatin1String進行比較:
if (attribute.name() == QLatin1String("http-contents-length")) //...
注意:某些編譯器編碼包含US-ASCII字符集以外字符的字串會有bug,在這種情況下,請確保在字串前加上u,否則是可選的,
原始碼
我們查看宏定義原始碼
template <int N>
struct QStaticStringData
{
QArrayData str;
qunicodechar data[N + 1];
QStringData *data_ptr() const
{
Q_ASSERT(str.ref.isStatic());
return const_cast<QStringData *>(static_cast<const QStringData*>(&str));
}
};
struct Q_CORE_EXPORT QArrayData
{
QtPrivate::RefCount ref;
int size;
uint alloc : 31;
uint capacityReserved : 1;
qptrdiff offset; // in bytes from beginning of header
}
#define QStringLiteral(str) \
([]() Q_DECL_NOEXCEPT -> QString { \
enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
static const QStaticStringData<Size> qstring_literal = { \
Q_STATIC_STRING_DATA_HEADER_INITIALIZER(Size), \
QT_UNICODE_LITERAL(str) }; \
QStringDataPtr holder = { qstring_literal.data_ptr() }; \
const QString qstring_literal_temp(holder); \
return qstring_literal_temp; \
}())
#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \
{ Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset }
#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER(size) \
Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, sizeof(QStringData))
我們對Q_STATIC_STRING_DATA_HEADER_INITIALIZER宏進行替換,可以得到
#define QStringLiteral(str) \
([]() Q_DECL_NOEXCEPT -> QString { \
// 計算大小,unicode為16bit一個字符,所以除2
enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
// 核心,只讀靜態變數,POD結構,編譯器創建
static const QStaticStringData<Size> qstring_literal = { \
// QArrayData
{-1, \
size, \
0, \
0, \
sizeof(QStringData) \
}, \
// qunicodechar []
QT_UNICODE_LITERAL(str) }; \
// 獲取編譯器創建的靜態底層資料
QStringDataPtr holder = { qstring_literal.data_ptr() }; \
// 構造QString,不用進行記憶體分配了
const QString qstring_literal_temp(holder); \
// 回傳QString,完成加速
return qstring_literal_temp; \
}())
小結
說白了,QStringLiteral在編譯期就創建了資料,避免了記憶體分配,加速了QString的創建,
原創造福大家,共享改變世界
獻出一片愛心,溫暖作者心靈
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/5202.html
標籤:其他
