QVector: preserve capacity in clear()

This is what std::vector implementations usually do,
because it minimizes memory fragmentation and useless
allocations since no user will call clear() unless
she intends to append new data afterwards.

Fix calls to resize(0) that show how existing code
tried to work around the issue.

Adjust test. Port from QVERIFY(==) to QCOMPARE as a
drive-by.

[ChangeLog][QtCore][QVector] clear() now preserves
capacity. To shed capacity, call squeeze() or swap
with a default-constructed QVector object, see the
documentation for an example.

Change-Id: I9cebe611a97e027a89e821e64408a4741b31f1f6
Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
This commit is contained in:
Marc Mutz 2016-02-16 15:24:38 +01:00
parent 85c2a128ef
commit a7885c9756
12 changed files with 31 additions and 21 deletions

View File

@ -286,7 +286,7 @@ void QEventDispatcherUNIXPrivate::markPendingSocketNotifiers()
} }
} }
pollfds.resize(0); pollfds.clear();
} }
int QEventDispatcherUNIXPrivate::activateSocketNotifiers() int QEventDispatcherUNIXPrivate::activateSocketNotifiers()
@ -480,8 +480,8 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
if (!canWait || (include_timers && d->timerList.timerWait(wait_tm))) if (!canWait || (include_timers && d->timerList.timerWait(wait_tm)))
tm = &wait_tm; tm = &wait_tm;
d->pollfds.clear();
d->pollfds.reserve(1 + (include_notifiers ? d->socketNotifiers.size() : 0)); d->pollfds.reserve(1 + (include_notifiers ? d->socketNotifiers.size() : 0));
d->pollfds.resize(0);
if (include_notifiers) if (include_notifiers)
for (auto it = d->socketNotifiers.cbegin(); it != d->socketNotifiers.cend(); ++it) for (auto it = d->socketNotifiers.cbegin(); it != d->socketNotifiers.cend(); ++it)

View File

@ -2335,7 +2335,7 @@ QRegExpCharClass::QRegExpCharClass()
void QRegExpCharClass::clear() void QRegExpCharClass::clear()
{ {
c = 0; c = 0;
r.resize(0); r.clear();
n = false; n = false;
} }

View File

@ -502,8 +502,19 @@
/*! \fn void QVector::clear() /*! \fn void QVector::clear()
Removes all the elements from the vector and releases the memory used by Removes all the elements from the vector.
the vector.
\note Until Qt 5.6, this also released the memory used by
the vector. From Qt 5.7, the capacity is preserved. To shed
all capacity, swap with a default-constructed vector:
\code
QVector<T> v ...;
QVector<T>().swap(v);
Q_ASSERT(v.capacity() == 0);
\endcode
or call squeeze().
\sa squeeze()
*/ */
/*! \fn const T &QVector::at(int i) const /*! \fn const T &QVector::at(int i) const

View File

@ -419,7 +419,7 @@ void QVector<T>::resize(int asize)
} }
template <typename T> template <typename T>
inline void QVector<T>::clear() inline void QVector<T>::clear()
{ *this = QVector<T>(); } { resize(0); }
template <typename T> template <typename T>
inline const T &QVector<T>::at(int i) const inline const T &QVector<T>::at(int i) const
{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::at", "index out of range"); { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::at", "index out of range");

View File

@ -1020,10 +1020,8 @@ bool QXmlStreamReaderPrivate::parse()
prefix.clear(); prefix.clear();
qualifiedName.clear(); qualifiedName.clear();
namespaceUri.clear(); namespaceUri.clear();
if (publicNamespaceDeclarations.size())
publicNamespaceDeclarations.clear(); publicNamespaceDeclarations.clear();
if (attributes.size()) attributes.clear();
attributes.resize(0);
if (isEmptyElement) { if (isEmptyElement) {
setType(QXmlStreamReader::EndElement); setType(QXmlStreamReader::EndElement);
Tag &tag = tagStack_pop(); Tag &tag = tagStack_pop();

View File

@ -375,7 +375,7 @@ QKeySequence::SequenceMatch QShortcutMap::nextState(QKeyEvent *e)
QKeySequence::SequenceMatch result = QKeySequence::NoMatch; QKeySequence::SequenceMatch result = QKeySequence::NoMatch;
// We start fresh each time.. // We start fresh each time..
d->identicals.resize(0); d->identicals.clear();
result = find(e); result = find(e);
if (result == QKeySequence::NoMatch && (e->modifiers() & Qt::KeypadModifier)) { if (result == QKeySequence::NoMatch && (e->modifiers() & Qt::KeypadModifier)) {
@ -448,7 +448,7 @@ QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e, int ignoredModifier
} }
// Looking for new identicals, scrap old // Looking for new identicals, scrap old
d->identicals.resize(0); d->identicals.clear();
bool partialFound = false; bool partialFound = false;
bool identicalDisabledFound = false; bool identicalDisabledFound = false;

View File

@ -2166,7 +2166,7 @@ void Parser::init(const QString &css, bool isFile)
} }
hasEscapeSequences = false; hasEscapeSequences = false;
symbols.resize(0); symbols.clear();
symbols.reserve(8); symbols.reserve(8);
Scanner::scan(Scanner::preprocess(styleSheet, &hasEscapeSequences), &symbols); Scanner::scan(Scanner::preprocess(styleSheet, &hasEscapeSequences), &symbols);
index = 0; index = 0;

View File

@ -1128,7 +1128,7 @@ void QTextDocumentPrivate::clearUndoRedoStacks(QTextDocument::Stacks stacksToCle
delete c.custom; delete c.custom;
} }
undoState = 0; undoState = 0;
undoStack.resize(0); undoStack.clear();
if (emitSignals && undoCommandsAvailable) if (emitSignals && undoCommandsAvailable)
emitUndoAvailable(false); emitUndoAvailable(false);
if (emitSignals && redoCommandsAvailable) if (emitSignals && redoCommandsAvailable)

View File

@ -516,7 +516,7 @@ QVector<QRect> MinOverlapPlacer::findMaxOverlappers(const QRect &domain, const Q
if (overlap >= maxOverlap || maxOverlap == -1) { if (overlap >= maxOverlap || maxOverlap == -1) {
if (overlap > maxOverlap) { if (overlap > maxOverlap) {
maxOverlap = overlap; maxOverlap = overlap;
result.resize(0); result.clear();
} }
result << srcRect; result << srcRect;
} }

View File

@ -200,7 +200,7 @@ void QMenuBarPrivate::updateGeometries()
if(itemsDirty) { if(itemsDirty) {
for(int j = 0; j < shortcutIndexMap.size(); ++j) for(int j = 0; j < shortcutIndexMap.size(); ++j)
q->releaseShortcut(shortcutIndexMap.value(j)); q->releaseShortcut(shortcutIndexMap.value(j));
shortcutIndexMap.resize(0); // faster than clear shortcutIndexMap.clear();
const int actionsCount = actions.count(); const int actionsCount = actions.count();
shortcutIndexMap.reserve(actionsCount); shortcutIndexMap.reserve(actionsCount);
for (int i = 0; i < actionsCount; i++) for (int i = 0; i < actionsCount; i++)

View File

@ -1141,7 +1141,7 @@ void QTextBrowser::clearHistory()
d->forwardStack.clear(); d->forwardStack.clear();
if (!d->stack.isEmpty()) { if (!d->stack.isEmpty()) {
QTextBrowserPrivate::HistoryEntry historyEntry = d->stack.top(); QTextBrowserPrivate::HistoryEntry historyEntry = d->stack.top();
d->stack.resize(0); d->stack.clear();
d->stack.push(historyEntry); d->stack.push(historyEntry);
d->home = historyEntry.url; d->home = historyEntry.url;
} }

View File

@ -734,10 +734,11 @@ void tst_QVector::clear() const
QVector<T> myvec; QVector<T> myvec;
myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2); myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2);
QVERIFY(myvec.size() == 3); const auto oldCapacity = myvec.capacity();
QCOMPARE(myvec.size(), 3);
myvec.clear(); myvec.clear();
QVERIFY(myvec.size() == 0); QCOMPARE(myvec.size(), 0);
QVERIFY(myvec.capacity() == 0); QCOMPARE(myvec.capacity(), oldCapacity);
} }
void tst_QVector::clearInt() const void tst_QVector::clearInt() const
@ -1945,7 +1946,7 @@ void tst_QVector::resizePOD() const
const int capacity = vector.capacity(); const int capacity = vector.capacity();
vector.resize(0); vector.clear();
QCOMPARE(vector.size(), 0); QCOMPARE(vector.size(), 0);
QVERIFY(vector.capacity() <= capacity); QVERIFY(vector.capacity() <= capacity);
} }