隱式共享

Qt 中的很多 C++ 類使用隱式數據共享,以最大化利用資源並最小化拷貝。隱式共享類既安全又高效當作為參數傳遞時,因為僅傳遞指嚮數據的指針,且僅當函數寫入時纔拷貝數據,即 寫入時拷貝 .

概述

共享類由指嚮包含引用計數和引用數據的共享數據塊的指針組成。

當創建共享對象時,它將引用計數設為 1。遞增引用計數,每當新對象引用共享數據時。和遞減引用計數,當對象解引用共享數據時。刪除共享數據,當引用計數變為 0 時。

When dealing with shared objects, there are two ways of copying an object. We usually speak about deep and shallow copies. A deep copy implies duplicating an object. A shallow copy is a reference copy, i.e. just a pointer to a shared data block. Making a deep copy can be expensive in terms of memory and CPU. Making a shallow copy is very fast, because it only involves setting a pointer and incrementing the reference count.

Object assignment (with operator=()) for implicitly shared objects is implemented using shallow copies.

The benefit of sharing is that a program does not need to duplicate data unnecessarily, which results in lower memory use and less copying of data. Objects can easily be assigned, sent as function arguments, and returned from functions.

Implicit sharing mostly takes place behind the scenes; the programmer rarely needs to worry about it. However, Qt's container iterators have different behavior than those from the STL. Read 隱式共享迭代器問題 .

In multithreaded applications, implicit sharing takes place, as explained in 綫程和隱式共享類 .

當實現自己的隱式共享類時,使用 QSharedData and QSharedDataPointer 類。

隱式共享細節

Implicit sharing automatically detaches the object from a shared block if the object is about to change and the reference count is greater than one. (This is often called 寫入時拷貝 or 值語義 )。

An implicitly shared class has control of its internal data. In any member functions that modify its data, it automatically detaches before modifying the data. Notice, however, the special case with container iterators; see 隱式共享迭代器問題 .

The QPen class, which uses implicit sharing, detaches from the shared data in all member functions that change the internal data.

代碼片段:

void QPen::setStyle(Qt::PenStyle style)
{
    detach();           // detach from common data
    d->style = style;   // set the style member
}
void QPen::detach()
{
    if (d->ref != 1) {
        ...             // perform a deep copy
    }
}
					
					

類列錶

The classes listed below automatically detach from common data if an object is about to be changed. The programmer will not even notice that the objects are shared. Thus you should treat separate instances of them as separate objects. They will always behave as separate objects but with the added benefit of sharing data whenever possible. For this reason, you can pass instances of these classes as arguments to functions by value without concern for the copying overhead.

範例:

QPixmap p1, p2;
p1.load("image.bmp");
p2 = p1;                        // p1 and p2 share data
QPainter paint;
paint.begin(&p2);               // cuts p2 loose from p1
paint.drawText(0,50, "Hi");
paint.end();
					

在此範例中, p1 and p2 共享數據直到 QPainter::begin () 被調用對於 p2 ,因為描繪像素圖會修改它。

警告: 小心拷貝隱式共享容器 ( QMap , QVector ,等) 當使用 STL 樣式迭代器 。見 隱式共享迭代器問題 .

QDebug 調試信息輸齣流
QDir 訪問目錄結構及其內容
QFileInfo 與係統無關的文件信息
QProcessEnvironment 保持可以被傳遞給程序的環境變量
QStorageInfo 提供有關當前掛載的存儲和驅動器的信息
QUrl 用於操控 URL 的方便接口
QUrlQuery 在 URL 的查詢中操縱鍵/值對的方法
QPersistentModelIndex 用於在數據模型中定位數據
QJsonArray 封裝 JSON 數組
QJsonDocument 讀寫 JSON 文檔的辦法
QJsonParseError 用於在 JSON 剖析期間報告錯誤
QJsonObject 封裝 JSON 對象
QJsonValue 把值封裝在 JSON 中
QVariant 舉動像最常見 Qt 數據類型的並集
QMimeType 描述由 MIME 類型字符串錶示的文件或數據的類型
QBitArray 位數組
QByteArray 字節數組
QByteArrayList 字節數組列錶
QCache 提供緩存的模闆類
QCollator 根據本地整理算法比較字符串
QCollatorSortKey 可以用於加速字符串整理
QCommandLineOption 定義可能的命令行選項
QContiguousCache 提供連續緩存的模闆類
QDateTime 日期和時間功能
QHash 提供基於哈希錶的字典的模闆類
QMultiHash 提供多值哈希的方便 QHash 子類
QLinkedList 提供鏈接列錶的模闆類
QList 提供列錶的模闆類
QLocale 在數字及其各種語言的字符串錶示之間轉換
QMap 提供基於紅-黑-樹的字典的模闆類
QMultiMap 提供多值映射的方便 QMap 子類
QQueue 提供隊列的通用容器
QRegExp 使用正則錶達式進行模式匹配
QRegularExpression 使用正則錶達式進行模式匹配
QRegularExpressionMatch QRegularExpression 針對字符串進行匹配的結果
QRegularExpressionMatchIterator QRegularExpression 對象針對字符串的全局匹配結果迭代器
QSet 提供基於哈希錶的集的模闆類
QStack 提供堆棧的模闆類
QString Unicode 字符串
QStringList 字符串列錶
QTextBoundaryFinder 在字符串中查找 Unicode 文本邊界的辦法
QVector 提供動態數組的模闆類
QDBusPendingCall 引用一待決異步調用
QDBusUnixFileDescriptor 保持一 Unix 文件描述符
QBitmap 單色 (1 位深度) 像素圖
QIcon 在不同模式和狀態下的可伸縮圖標
QImage 獨立於硬件的圖像錶示 (允許直接訪問像素數據,且可以被用作描繪設備)
QPicture 用於記錄和重演 QPainter 命令的描繪設備
QPixmap 可以用作描繪設備的離屏圖像錶示
QCursor 具有任意形狀的鼠標光標
QKeySequence 封裝作為快捷鍵使用的鍵序列
QPalette 包含各 Widget 狀態的顔色組
QOpenGLDebugMessage 包裹 OpenGL 調試消息
QBrush 定義 QPainter 繪製形狀的填充圖案
QGradient 用於組閤 QBrush 以指定漸變填充
QPainterPath 用於描繪操作的容器,使圖形形狀能夠被構造和重用
QPen 定義 QPainter 如何繪製綫條和形狀的輪廓
QPolygon 使用整數精度的點嚮量
QPolygonF 使用浮點精度的點嚮量
QRegion 為描繪器指定裁剪區域
QFont Specifies a font used for drawing text
QFontInfo 有關字體的一般信息
QFontMetrics 字體規格信息
QFontMetricsF 字體規格信息
QGlyphRun 直接訪問字體中的內部字形
QRawFont 訪問字體的單物理實例
QStaticText 當文本及其布局很少更新時,啓用優化文本繪製
QTextCursor 提供訪問和修改 QTextDocument 的 API
QTextDocumentFragment 錶示一塊來自 QTextDocument 的格式化文本
QTextBlockFormat 用於 QTextDocument 文本塊的格式化信息
QTextCharFormat 用於 QTextDocument 字符的格式化信息
QTextFormat 用於 QTextDocument 的格式化信息
QTextFrameFormat 用於 QTextDocument 框架的格式化信息
QTextImageFormat 用於 QTextDocument 圖像的格式化信息
QTextListFormat 用於 QTextDocument 列錶的格式化信息
QTextTableCellFormat 用於 QTextDocument 中錶格單元格的格式化信息
QTextTableFormat 用於 QTextDocument 中錶格的格式化信息
QNetworkCacheMetaData 緩存信息
QHttpPart 保持本體部分 (要在 HTTP 多部分 MIME 消息內使用)
QNetworkCookie 保持一網絡 Cookie
QNetworkRequest 保持要采用 QNetworkAccessManager 發送的請求
QNetworkConfiguration 一個或多個訪問點配置的抽象
QDnsDomainNameRecord 存儲域名記錄的有關信息
QDnsHostAddressRecord 存儲有關主機地址記錄的信息
QDnsMailExchangeRecord 存儲有關 DNS MX 記錄的信息
QDnsServiceRecord 存儲有關 DNS SRV 記錄的信息
QDnsTextRecord 存儲有關 DNS TXT 記錄的信息
QHostAddress IP 地址
QNetworkAddressEntry 存儲由網絡接口支持的一個 IP 地址及其關聯的 Netmask (網絡掩碼) 和廣播地址
QNetworkInterface 主機的 IP 地址和網絡接口列錶
QNetworkProxy 網絡層代理
QNetworkProxyQuery 用於查詢套接字的代理設置
QSslCertificate 用於 X509 證書的便捷 API
QSslCertificateExtension 用於訪問 X509 證書擴展名的 API
QSslCipher 錶示 SSL 加密密碼
QSslConfiguration 保持 SSL 連接的配置和狀態
QSslDiffieHellmanParameters 用於服務器的 Diffie-Hellman 參數的接口
QSslError SSL 錯誤
QSslKey 用於私鑰和公鑰的接口
QSslPreSharedKeyAuthenticator 用於 PSK (預共享密鑰) 密碼套件的身份驗證數據
QSqlField 操縱 SQL 數據庫錶和視圖中的字段
QSqlQuery 執行和操縱 SQL 語句的手段
QSqlRecord 封裝數據庫記錄
QLowEnergyAdvertisingData 錶示藍牙低功耗廣告期間要廣播的數據
QLowEnergyAdvertisingParameters 錶示用於藍牙低功耗廣告的參數
QLowEnergyCharacteristicData 用於設置 GATT 服務數據
QLowEnergyConnectionParameters 當請求或報告藍牙 LE 連接的參數更新時使用
QLowEnergyDescriptorData 用於創建 GATT 服務數據
QLowEnergyServiceData 用於設置 GATT 服務數據