一些Qt函数返回一个容器,如果想使用STL风格的迭代器遍历某函数的返回值,就必须复制此容器并且遍历这个副本,例如,下面的代码给出了如何遍历由QSplitter::sizes()返回的QList<int>的正确方式。
// RIGHT
const QList<int> sizes = splitter->sizes();
QList<int>::const_iterator i;
for (i = sizes.begin(); i != sizes.end(); ++i)
...
// WRONG
QList<int>::const_iterator i;
for (i = splitter->sizes().begin();
i != splitter->sizes().end(); ++i)
...
错误的原因是,每次调用QSplitter::sizes()都返回一个新的QList<int>值,如果不存储这个值,C++在开始迭代之前就会自动将其销毁,而只留下一个浮动迭代器。更糟的是,每次循环运行由于都调用了splitter->sizes().end(),QSplitter::sizes()都必须生成一个新的列表的副本。总之,如果你使用STL风格迭代器,总是要在返回值的容器副本上进行遍历。而Java Style不需要,因为它自动生成了副本。
采用隐式共享,我们复制一个容器就像复制一个指针一样快。只有复制项之一发生改变时,数据才会实际被复制,而且这一切操作都可以在后台自动处理,由于这原因,隐式共享也叫“写时复制”。
隐式共享的优点是它是一个我们必须要考虑的最优化过程,它工作不需要我们干预,同时,隐式共享也提倡由值返回的对象的整洁编程风格。
很多类都是隐式共享的,除了容器类外还有QByteArray, QBrush, QFont, QPen, QImage, QPixmap, QString, QVariant 等等。
一个共享类对象创建,它的引用计数就记为1,如果将它传递给另一个对象,那计数就加1,并两个对象都指向内存中的相同的内部数据结构。如果某一个修改了对象值就会发生深度复制,以确保他们指向的数据结构不相同。并且之前的数据计数将减1,修改后的数据计数就为1。为1表示没有被共享。
这里简单讲下深度复制和浅度复制。
当处理一个共享对象时,我们有两种拷贝一个对象的方法:也就是我们常说的深度和浅度复制。深度复制是复制一个对象,浅度是复制一个对象引用,也就是说一个指针的共享数据块。显然使用浅度复制会很快。
隐式共享对象的复制操作符(operator=)是用浅度复制实现的。
当我们要实现自己的隐式共享类时,使用QSharedData, QSharedDataPointer类。
如果对象会改变或者引用计数是比另个更大,隐式共享就会自动从共享块中分离。一个隐式共享类完全控制它内部数据,如果任何成员函数修改了它的值,隐式共享都会在修改数据前自动分离。
例如QPen (它是隐式共享类),那些改变内部数据的所有成员函数分离共享数据:
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
}
}
下面列出的类,如果一个对象被改变都会从共享数据中自动分离。编程者不需要注意这些类是共享的。因此要区别对待这些类的实例。这样,就可以作为参数传递这些实例而不关心复制代价了。
例子:
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 p2共享数据,直到为p2调用begin()。
注意:你用non-const STL风格迭代器遍历容器(隐式共享容器,例如QMap,QVector等)时不需要复制容器。正如最开始讲的那个问题。
QBitmap |
|
QIcon |
|
QImage |
|
QPicture |
|
QPixmap |
|
QCursor |
|
QKeySequence |
|
QPalette |
|
QBrush |
|
QGradient |
|
QPainterPath |
|
QPen |
|
QPolygon |
|
QPolygonF |
|
QRegion |
|
QFont |
|
QFontInfo |
|
QFontMetrics |
|
QFontMetricsF |
|
QGlyphRun |
|
QRawFont |
|
QStaticText |
|
QTextCursor |
|
QTextDocumentFragment |
|
QTextBlockFormat |
|
QTextCharFormat |
|
QTextFormat |
|
QTextFrameFormat |
|
QTextImageFormat |
|
QTextListFormat |
|
QTextTableCellFormat |
|
QTextTableFormat |
|
QNetworkCacheMetaData |
|
QHttpPart |
|
QNetworkCookie |
|
QNetworkRequest |
|
QNetworkConfiguration |
|
QDnsDomainNameRecord |
|
QDnsHostAddressRecord |
|
QDnsMailExchangeRecord |
|
QDnsServiceRecord |
|
QDnsTextRecord |
|
QNetworkAddressEntry |
|
QNetworkInterface |
|
QNetworkProxy |
|
QNetworkProxyQuery |
|
QSslCertificate |
|
QSslCertificateExtension |
|
QSslCipher |
|
QSslConfiguration |
|
QSslError |
|
QSslKey |
|
QDebug |
Output stream for debugging information |
QDir |
Access to directory structures and their contents |
QFileInfo |
System-independent file information |
QProcessEnvironment |
Holds the environment variables that can be passed to a program |
QUrl |
Convenient interface for working with URLs |
QUrlQuery |
Way to manipulate a key-value pairs in a URL's query |
QPersistentModelIndex |
Used to locate data in a data model |
QVariant |
Acts like a union for the most common Qt data types |
QMimeType |
Describes types of file or data, represented by a MIME type string |
QBitArray |
Array of bits |
QByteArray |
Array of bytes |
QCache |
Template class that provides a cache |
QContiguousCache |
Template class that provides a contiguous cache |
QDateTime |
Date and time functions |
QHash |
Template class that provides a hash-table-based dictionary |
QMultiHash |
Convenience QHash subclass that provides multi-valued hashes |
QLinkedList |
Template class that provides linked lists |
QList |
Template class that provides lists |
QLocale |
Converts between numbers and their string representations in various languages |
QMap |
Template class that provides a red-black-tree-based dictionary |
QMultiMap |
Convenience QMap subclass that provides multi-valued maps |
QQueue |
Generic container that provides a queue |
QRegExp |
Pattern matching using regular expressions |
QRegularExpression |
Pattern matching using regular expressions |
QRegularExpressionMatch |
The results of a matching a QRegularExpression against a string |
QRegularExpressionMatchIterator |
Iterator on the results of a global match of a QRegularExpression object against a string |
QSet |
Template class that provides a hash-table-based set |
QStack |
Template class that provides a stack |
QString |
Unicode character string |
QStringList |
List of strings |
QTextBoundaryFinder |
Way of finding Unicode text boundaries in a string |
QVector |
Template class that provides a dynamic array |