Add support for multiple arguments to QSharedPointer::create()

Requires C++11 rvalue references and variadic templates so we can
implement perfect forwarding.

Change-Id: I62e47d1ffd0c61e8386f9f246aa79031b7430b46
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
Thiago Macieira 2012-05-23 21:10:31 +02:00 committed by The Qt Project
parent f4b4b4414e
commit 7ee9551b62
4 changed files with 181 additions and 0 deletions

View File

@ -604,6 +604,37 @@
\sa qSharedPointerObjectCast()
*/
/*!
\fn QSharedPointer<T> QSharedPointer::create()
\since 4.6
Creates a QSharedPointer object and allocates a new item of type \tt T. The
QSharedPointer internals and the object are allocated in one single memory
allocation, which could help reduce memory fragmentation in a long-running
application.
This function calls the default constructor for type \tt T.
*/
/*!
\fn QSharedPointer<T> QSharedPointer::create(...)
\overload
\since 5.1
Creates a QSharedPointer object and allocates a new item of type \tt T. The
QSharedPointer internals and the object are allocated in one single memory
allocation, which could help reduce memory fragmentation in a long-running
application.
This function will attempt to call a constructor for type \tt T that can
accept all the arguments passed. Arguments will be perfectly-forwarded.
\note This function is only available with a C++11 compiler that supports
perfect forwarding of an arbitrary number of arguments. If the compiler
does not support the necessary C++11 features, you must use the overload
that calls the default constructor.
*/
/*!
\fn QWeakPointer<T> QSharedPointer::toWeakRef() const

View File

@ -95,6 +95,9 @@ public:
template <class X> QSharedPointer<X> dynamicCast() const;
template <class X> QSharedPointer<X> constCast() const;
template <class X> QSharedPointer<X> objectCast() const;
static inline QSharedPointer<T> create();
static inline QSharedPointer<T> create(...);
};
template <class T>

View File

@ -62,6 +62,10 @@ QT_END_HEADER
#include <QtCore/qobject.h> // for qobject_cast
#include <QtCore/qhash.h> // for qHash
#if defined(Q_COMPILER_RVALUE_REFS) && defined(Q_COMPILER_VARIADIC_TEMPLATES)
# include <utility> // for std::forward
#endif
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
@ -389,6 +393,28 @@ public:
QWeakPointer<T> toWeakRef() const;
#if defined(Q_COMPILER_RVALUE_REFS) && defined(Q_COMPILER_VARIADIC_TEMPLATES)
template <typename... Args>
static QSharedPointer<T> create(Args && ...arguments)
{
typedef QtSharedPointer::ExternalRefCountWithContiguousData<T> Private;
# ifdef QT_SHAREDPOINTER_TRACK_POINTERS
typename Private::DestroyerFn destroy = &Private::safetyCheckDeleter;
# else
typename Private::DestroyerFn destroy = &Private::deleter;
# endif
QSharedPointer<T> result(Qt::Uninitialized);
result.d = Private::create(&result.value, destroy);
// now initialize the data
new (result.data()) T(std::forward<Args>(arguments)...);
result.d->setQObjectShared(result.value, true);
# ifdef QT_SHAREDPOINTER_TRACK_POINTERS
internalSafetyCheckAdd(result.d, result.value);
# endif
return result;
}
#else
static inline QSharedPointer<T> create()
{
typedef QtSharedPointer::ExternalRefCountWithContiguousData<T> Private;
@ -408,6 +434,7 @@ public:
result.d->setQObjectShared(result.value, true);
return result;
}
#endif
private:
explicit QSharedPointer(Qt::Initialization) {}

View File

@ -95,6 +95,7 @@ private slots:
void lambdaCustomDeleter();
#endif
void creating();
void creatingVariadic();
void creatingQObject();
void mixTrackingPointerCode();
void reentrancyWhileDestructing();
@ -174,6 +175,49 @@ public:
int Data::generationCounter = 0;
int Data::destructorCounter = 0;
struct NoDefaultConstructor1
{
int i;
NoDefaultConstructor1(int i) : i(i) {}
NoDefaultConstructor1(uint j) : i(j + 42) {}
};
struct NoDefaultConstructorRef1
{
int &i;
NoDefaultConstructorRef1(int &i) : i(i) {}
};
struct NoDefaultConstructor2
{
void *ptr;
int i;
NoDefaultConstructor2(void *ptr, int i) : ptr(ptr), i(i) {}
};
struct NoDefaultConstructorRef2
{
QString str;
int i;
NoDefaultConstructorRef2(QString &str, int i) : str(str), i(i) {}
};
struct NoDefaultConstructorConstRef2
{
QString str;
int i;
NoDefaultConstructorConstRef2(const QString &str, int i) : str(str), i(i) {}
NoDefaultConstructorConstRef2(const QByteArray &ba, int i = 42) : str(QString::fromLatin1(ba)), i(i) {}
};
#ifdef Q_COMPILER_RVALUE_REFS
struct NoDefaultConstructorRRef1
{
int &i;
NoDefaultConstructorRRef1(int &&i) : i(i) {}
};
#endif
void tst_QSharedPointer::basics_data()
{
QTest::addColumn<bool>("isNull");
@ -1429,6 +1473,82 @@ void tst_QSharedPointer::creating()
safetyCheck();
}
void tst_QSharedPointer::creatingVariadic()
{
#if !defined(Q_COMPILER_RVALUE_REFS) || !defined(Q_COMPILER_VARIADIC_TEMPLATES)
QSKIP("This compiler is not in C++11 mode or it doesn't support rvalue refs and variadic templates");
#else
int i = 42;
{
NoDefaultConstructor1(1); // control check
QSharedPointer<NoDefaultConstructor1> ptr = QSharedPointer<NoDefaultConstructor1>::create(1);
QCOMPARE(ptr->i, 1);
NoDefaultConstructor1(0u); // control check
ptr = QSharedPointer<NoDefaultConstructor1>::create(0u);
QCOMPARE(ptr->i, 42);
NoDefaultConstructor1 x(i); // control check
ptr = QSharedPointer<NoDefaultConstructor1>::create(i);
QCOMPARE(ptr->i, i);
}
{
NoDefaultConstructor2((void*)0, 1); // control check
QSharedPointer<NoDefaultConstructor2> ptr = QSharedPointer<NoDefaultConstructor2>::create((void*)0, 1);
QCOMPARE(ptr->i, 1);
QCOMPARE(ptr->ptr, (void*)0);
int *null = 0;
NoDefaultConstructor2(null, 2); // control check
ptr = QSharedPointer<NoDefaultConstructor2>::create(null, 2);
QCOMPARE(ptr->i, 2);
QCOMPARE(ptr->ptr, (void*)0);
#ifdef Q_COMPILER_NULLPTR
NoDefaultConstructor2(nullptr, 3); // control check
ptr = QSharedPointer<NoDefaultConstructor2>::create(nullptr, 3);
QCOMPARE(ptr->i, 3);
QCOMPARE(ptr->ptr, (void*)nullptr);
#endif
}
{
NoDefaultConstructorRef1 x(i); // control check
QSharedPointer<NoDefaultConstructorRef1> ptr = QSharedPointer<NoDefaultConstructorRef1>::create(i);
QCOMPARE(ptr->i, i);
QCOMPARE(&ptr->i, &i);
}
{
NoDefaultConstructorRRef1(1); // control check
QSharedPointer<NoDefaultConstructorRRef1> ptr = QSharedPointer<NoDefaultConstructorRRef1>::create(1);
QCOMPARE(ptr->i, 1);
NoDefaultConstructorRRef1(std::move(i)); // control check
ptr = QSharedPointer<NoDefaultConstructorRRef1>::create(std::move(i));
QCOMPARE(ptr->i, i);
}
{
QString text("Hello, World");
NoDefaultConstructorRef2(text, 1); // control check
QSharedPointer<NoDefaultConstructorRef2> ptr = QSharedPointer<NoDefaultConstructorRef2>::create(text, 1);
QCOMPARE(ptr->str, text);
QCOMPARE(ptr->i, 1);
}
{
QSharedPointer<NoDefaultConstructorConstRef2> ptr;
NoDefaultConstructorConstRef2(QLatin1String("string"), 1); // control check
ptr = QSharedPointer<NoDefaultConstructorConstRef2>::create(QLatin1String("string"), 1);
QCOMPARE(ptr->str, QString("string"));
QCOMPARE(ptr->i, 1);
NoDefaultConstructorConstRef2(QByteArray("bytearray")); // control check
ptr = QSharedPointer<NoDefaultConstructorConstRef2>::create(QByteArray("bytearray"));
QCOMPARE(ptr->str, QString("bytearray"));
QCOMPARE(ptr->i, 42);
}
#endif
}
void tst_QSharedPointer::creatingQObject()
{
{