Skip to content

Commit

Permalink
Add QObjectUniquePtr
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed Jun 10, 2019
1 parent 13099cc commit 01f2ba9
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -979,6 +979,7 @@ SET(QGIS_CORE_HDRS
qgstilecache.h
qgstracer.h
qgstranslationcontext.h
qobjectuniqueptr.h

qgsvectordataprovider.h
qgsvectorlayercache.h
Expand Down
106 changes: 106 additions & 0 deletions src/core/qobjectuniqueptr.h
@@ -0,0 +1,106 @@
#ifndef QOBJECTUNIQUEPTR_H
#define QOBJECTUNIQUEPTR_H

#include <qsharedpointer.h>
#include <qtypeinfo.h>

class QVariant;

template <class T>
class QObjectUniquePtr
{
Q_STATIC_ASSERT_X( !std::is_pointer<T>::value, "QObjectUniquePtr's template type must not be a pointer type" );

template<typename U>
struct TypeSelector
{
typedef QObject Type;
};
template<typename U>
struct TypeSelector<const U>
{
typedef const QObject Type;
};
typedef typename TypeSelector<T>::Type QObjectType;
QWeakPointer<QObjectType> wp;
public:
inline QObjectUniquePtr() { }
inline QObjectUniquePtr( T *p ) : wp( p ) { }
// compiler-generated copy/move ctor/assignment operators are fine!

~QObjectUniquePtr() { delete wp.data(); }

inline void swap( QObjectUniquePtr &other ) { wp.swap( other.wp ); }

inline QObjectUniquePtr<T> &operator=( T *p )
{ wp.assign( static_cast<QObjectType *>( p ) ); return *this; }

inline T *data() const
{ return static_cast<T *>( wp.data() ); }
inline T *operator->() const
{ return data(); }
inline T &operator*() const
{ return *data(); }
inline operator T *() const
{ return data(); }

inline bool isNull() const
{ return wp.isNull(); }

inline void clear()
{ wp.clear(); }

T *release() { T *p = qobject_cast<T *>( wp.data() ); wp.clear(); return p; }

void reset( T *p = nullptr ) { delete wp.data(); wp = p; }
};
template <class T> Q_DECLARE_TYPEINFO_BODY( QObjectUniquePtr<T>, Q_MOVABLE_TYPE );

template <class T>
inline bool operator==( const T *o, const QObjectUniquePtr<T> &p )
{ return o == p.operator->(); }

template<class T>
inline bool operator==( const QObjectUniquePtr<T> &p, const T *o )
{ return p.operator->() == o; }

template <class T>
inline bool operator==( T *o, const QObjectUniquePtr<T> &p )
{ return o == p.operator->(); }

template<class T>
inline bool operator==( const QObjectUniquePtr<T> &p, T *o )
{ return p.operator->() == o; }

template<class T>
inline bool operator==( const QObjectUniquePtr<T> &p1, const QObjectUniquePtr<T> &p2 )
{ return p1.operator->() == p2.operator->(); }

template <class T>
inline bool operator!=( const T *o, const QObjectUniquePtr<T> &p )
{ return o != p.operator->(); }

template<class T>
inline bool operator!= ( const QObjectUniquePtr<T> &p, const T *o )
{ return p.operator->() != o; }

template <class T>
inline bool operator!=( T *o, const QObjectUniquePtr<T> &p )
{ return o != p.operator->(); }

template<class T>
inline bool operator!= ( const QObjectUniquePtr<T> &p, T *o )
{ return p.operator->() != o; }

template<class T>
inline bool operator!= ( const QObjectUniquePtr<T> &p1, const QObjectUniquePtr<T> &p2 )
{ return p1.operator->() != p2.operator->() ; }

template<typename T>
QObjectUniquePtr<T>
QObjectUniquePtrFromVariant( const QVariant &variant )
{
return QObjectUniquePtr<T>( qobject_cast<T *>( QtSharedPointer::weakPointerFromVariant_internal( variant ).data() ) );
}

#endif // QOBJECTUNIQUEPTR_H
1 change: 1 addition & 0 deletions tests/src/core/CMakeLists.txt
Expand Up @@ -219,6 +219,7 @@ SET(TESTS
testqgsmimedatautils.cpp
testqgsofflineediting.cpp
testqgstranslateproject.cpp
testqobjectuniqueptr.cpp
)

IF(WITH_QTWEBKIT)
Expand Down
70 changes: 70 additions & 0 deletions tests/src/core/testqobjectuniqueptr.cpp
@@ -0,0 +1,70 @@
/***************************************************************************
testqobjectuniqueptr.cpp
--------------------------------------
Date :
Copyright : (C) 2019 by Matthias Kuhn
Email : matthias@opengis.ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgstest.h"
#include "qobjectuniqueptr.h"

#include "qgstest.h"

class TestQObjectUniquePtr : public QObject
{
Q_OBJECT

private slots:
void testMemLeak();
void testParentDeletedFirst();
void testParentDeletedAfter();
};



void TestQObjectUniquePtr::testMemLeak()
{
QObject *myobj = new QObject();
QObjectUniquePtr<QObject> obj( myobj );
}

void TestQObjectUniquePtr::testParentDeletedFirst()
{
QObject *parent = new QObject();
QObject *child = new QObject( parent );

QObjectUniquePtr<QObject> obj( child );
QVERIFY( !obj.isNull() );

delete parent;
QVERIFY( obj.isNull() );
}

void TestQObjectUniquePtr::testParentDeletedAfter()
{
QObject *parent = new QObject();
QObject *child = new QObject( parent );
QPointer<QObject> observer( child );

{
QObjectUniquePtr<QObject> obj( child );
QVERIFY( !observer.isNull() );
}
QVERIFY( observer.isNull() );


// Basically shouldn't crash because of double delete on this line
delete parent;
QVERIFY( observer.isNull() );
}

QGSTEST_MAIN( TestQObjectUniquePtr )
#include "testqobjectuniqueptr.moc"

0 comments on commit 01f2ba9

Please sign in to comment.