Implement move-ctor and move-assignment-op for QScopedPointer
It makes sense for a QScopedPointer to be movable, for instance for allowing instances to be returned from a function. Ownwership of the managed pointer is still tied to one (and one only) QScopedPointer instance. Moreover, a move assignment operator makes sense as well, as it implementing the equivalent of this->reset(other.take()); only when other is a rvalue and not a lvalue (so either it's a temporary or it's getting explicitly moved in with std::move). This makes QScopedPointer API's a bit closer to std::unique_ptr's one. Task-number: QTBUG-29754 Change-Id: If1ac0c688327a67af4ad5b7ad45b439b022ed1c6 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>bb10
parent
69b31f7b65
commit
5b9006bbdb
|
|
@ -130,6 +130,33 @@ QT_BEGIN_NAMESPACE
|
|||
Constructs this QScopedPointer instance and sets its pointer to \a p.
|
||||
*/
|
||||
|
||||
#ifndef Q_QDOC // QTBUG-32675, qdoc can't parse rvalue refs
|
||||
/*!
|
||||
\fn QScopedPointer::QScopedPointer(QScopedPointer<T, Cleanup> &&other)
|
||||
|
||||
Move-constructs a QScopedPointer instance, making it point at the same
|
||||
object that \a other was pointing to. \a other is reset to point to \c{NULL}.
|
||||
|
||||
\since 5.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn QScopedPointer<T, Cleanup> &operator=(QScopedPointer<T, Cleanup> &&other)
|
||||
|
||||
Move-assigns \a other to this QScopedPointer instance, transferring the
|
||||
ownership of the managed pointer to this instance.
|
||||
|
||||
If \a other and this instance are actually the same object, this operator
|
||||
does nothing.
|
||||
|
||||
Otherwise, this instance is set to point to the object \a other
|
||||
is pointing to, and \a other is set to point to \c{NULL}.
|
||||
If this instance was pointing to an object, that object is destroyed,
|
||||
|
||||
\since 5.2
|
||||
*/
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\fn QScopedPointer::~QScopedPointer()
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,19 @@ public:
|
|||
Cleanup::cleanup(oldD);
|
||||
}
|
||||
|
||||
#ifdef Q_COMPILER_RVALUE_REFS
|
||||
inline QScopedPointer(QScopedPointer<T, Cleanup> &&other)
|
||||
: d(other.take())
|
||||
{
|
||||
}
|
||||
|
||||
inline QScopedPointer<T, Cleanup> &operator=(QScopedPointer<T, Cleanup> &&other)
|
||||
{
|
||||
reset(other.take());
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline T &operator*() const
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
CONFIG += testcase parallel_test
|
||||
contains(QT_CONFIG, c++11):CONFIG += c++11
|
||||
TARGET = tst_qscopedpointer
|
||||
QT = core testlib
|
||||
SOURCES = tst_qscopedpointer.cpp
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@
|
|||
#include <QtTest/QtTest>
|
||||
#include <QtCore/QScopedPointer>
|
||||
|
||||
#include <utility>
|
||||
|
||||
/*!
|
||||
\class tst_QScopedPointer
|
||||
\internal
|
||||
|
|
@ -73,6 +75,7 @@ private Q_SLOTS:
|
|||
void objectSize();
|
||||
void comparison();
|
||||
void array();
|
||||
void move();
|
||||
// TODO instanciate on const object
|
||||
};
|
||||
|
||||
|
|
@ -458,6 +461,158 @@ void tst_QScopedPointer::array()
|
|||
QCOMPARE(instCount, RefCounted::instanceCount.load());
|
||||
}
|
||||
|
||||
#ifdef Q_COMPILER_RVALUE_REFS
|
||||
struct CountedInteger
|
||||
{
|
||||
CountedInteger(int i) : i(i)
|
||||
{
|
||||
++instanceCount;
|
||||
}
|
||||
~CountedInteger()
|
||||
{
|
||||
--instanceCount;
|
||||
}
|
||||
CountedInteger(const CountedInteger &c)
|
||||
: i(c.i)
|
||||
{
|
||||
++instanceCount;
|
||||
}
|
||||
|
||||
static int instanceCount;
|
||||
int i;
|
||||
};
|
||||
|
||||
int CountedInteger::instanceCount = 0;
|
||||
|
||||
QScopedPointer<CountedInteger> returnScopedPointer(int i)
|
||||
{
|
||||
return QScopedPointer<CountedInteger>(new CountedInteger(i));
|
||||
}
|
||||
#endif
|
||||
|
||||
void tst_QScopedPointer::move()
|
||||
{
|
||||
#ifndef Q_COMPILER_RVALUE_REFS
|
||||
QSKIP("This test requires rvalues refs");
|
||||
#else
|
||||
QCOMPARE(CountedInteger::instanceCount, 0);
|
||||
|
||||
{
|
||||
QScopedPointer<CountedInteger> p = returnScopedPointer(42);
|
||||
QVERIFY(!p.isNull());
|
||||
QCOMPARE(p->i, 42);
|
||||
QCOMPARE(CountedInteger::instanceCount, 1);
|
||||
|
||||
QScopedPointer<CountedInteger> q = returnScopedPointer(51);
|
||||
QVERIFY(!q.isNull());
|
||||
QCOMPARE(q->i, 51);
|
||||
QCOMPARE(CountedInteger::instanceCount, 2);
|
||||
|
||||
q = returnScopedPointer(123);
|
||||
QVERIFY(!q.isNull());
|
||||
QCOMPARE(q->i, 123);
|
||||
QCOMPARE(CountedInteger::instanceCount, 2);
|
||||
|
||||
p = std::move(q);
|
||||
QVERIFY(!p.isNull());
|
||||
QCOMPARE(p->i, 123);
|
||||
QVERIFY(q.isNull());
|
||||
QCOMPARE(CountedInteger::instanceCount, 1);
|
||||
|
||||
p = std::move(q);
|
||||
QVERIFY(p.isNull());
|
||||
QVERIFY(q.isNull());
|
||||
QCOMPARE(CountedInteger::instanceCount, 0);
|
||||
}
|
||||
|
||||
QCOMPARE(CountedInteger::instanceCount, 0);
|
||||
|
||||
{
|
||||
QScopedPointer<CountedInteger> p = returnScopedPointer(1024);
|
||||
QVERIFY(!p.isNull());
|
||||
QCOMPARE(p->i, 1024);
|
||||
QCOMPARE(CountedInteger::instanceCount, 1);
|
||||
|
||||
p.reset();
|
||||
QVERIFY(p.isNull());
|
||||
QCOMPARE(CountedInteger::instanceCount, 0);
|
||||
|
||||
p = returnScopedPointer(1024);
|
||||
const CountedInteger * const rawPtr = p.data();
|
||||
p = std::move(p);
|
||||
// now p is in a "valid, but unspecified state". so the test must not crash.
|
||||
// we do actually know that this move should've been a noop.
|
||||
QVERIFY(!p.isNull());
|
||||
QCOMPARE(p.data(), rawPtr);
|
||||
QCOMPARE(p->i, 1024);
|
||||
QCOMPARE(CountedInteger::instanceCount, 1);
|
||||
|
||||
p.reset();
|
||||
QVERIFY(p.isNull());
|
||||
QCOMPARE(CountedInteger::instanceCount, 0);
|
||||
}
|
||||
|
||||
QCOMPARE(CountedInteger::instanceCount, 0);
|
||||
|
||||
{
|
||||
QScopedPointer<CountedInteger> p = returnScopedPointer(-1);
|
||||
QVERIFY(!p.isNull());
|
||||
QCOMPARE(p->i, -1);
|
||||
QCOMPARE(CountedInteger::instanceCount, 1);
|
||||
}
|
||||
|
||||
QCOMPARE(CountedInteger::instanceCount, 0);
|
||||
|
||||
{
|
||||
QScopedPointer<CountedInteger> p = returnScopedPointer(0);
|
||||
QVERIFY(!p.isNull());
|
||||
QCOMPARE(p->i, 0);
|
||||
QCOMPARE(CountedInteger::instanceCount, 1);
|
||||
|
||||
QScopedPointer<CountedInteger> q;
|
||||
QVERIFY(q.isNull());
|
||||
|
||||
p = std::move(q);
|
||||
QVERIFY(p.isNull());
|
||||
QVERIFY(q.isNull());
|
||||
QCOMPARE(CountedInteger::instanceCount, 0);
|
||||
}
|
||||
|
||||
QCOMPARE(CountedInteger::instanceCount, 0);
|
||||
|
||||
{
|
||||
QScopedPointer<CountedInteger> p;
|
||||
QVERIFY(p.isNull());
|
||||
QCOMPARE(CountedInteger::instanceCount, 0);
|
||||
|
||||
QScopedPointer<CountedInteger> q = returnScopedPointer(123);
|
||||
QVERIFY(!q.isNull());
|
||||
QCOMPARE(q->i, 123);
|
||||
QCOMPARE(CountedInteger::instanceCount, 1);
|
||||
|
||||
p = std::move(q);
|
||||
QVERIFY(!p.isNull());
|
||||
QCOMPARE(p->i, 123);
|
||||
QVERIFY(q.isNull());
|
||||
QCOMPARE(CountedInteger::instanceCount, 1);
|
||||
}
|
||||
|
||||
QCOMPARE(CountedInteger::instanceCount, 0);
|
||||
|
||||
{
|
||||
QScopedPointer<CountedInteger> p;
|
||||
QVERIFY(p.isNull());
|
||||
QCOMPARE(CountedInteger::instanceCount, 0);
|
||||
|
||||
p = returnScopedPointer(2001);
|
||||
QVERIFY(!p.isNull());
|
||||
QCOMPARE(p->i, 2001);
|
||||
QCOMPARE(CountedInteger::instanceCount, 1);
|
||||
}
|
||||
|
||||
QCOMPARE(CountedInteger::instanceCount, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QScopedPointer)
|
||||
#include "tst_qscopedpointer.moc"
|
||||
|
|
|
|||
Loading…
Reference in New Issue