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:
parent
f4b4b4414e
commit
7ee9551b62
@ -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
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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) {}
|
||||
|
@ -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()
|
||||
{
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user