Since Qt uses its horrible archaic ptr mechanisms, using their QSharedPointer
is mostly not practical.
The moment you set a QSharedPointer
to nullptr
while being in a slot could very well result in undefined behavior (crashing). Also, the design of QSharedPointer
does have the wrong design decisions in contrast to std::shared_ptr
.
So I thought about a proper shared pointer, which could be used also in slots.
What I came up is the following:
template <typename T>
struct LateDeleter {
void operator()( T* ptr ) {
if( !ptr )
return;
auto qObject = static_cast<QObject*>( ptr );
qObject->deleteLater();
}
};
template <typename T>
class QSharedPtr : public std::shared_ptr<T> {
public:
typedef std::shared_ptr<T> __base;
#ifdef Q_OS_WIN
QSharedPtr() : __base( nullptr, LateDeleter<T>() ) {}
#else
constexpr QSharedPtr() : __base( nullptr, LateDeleter<T>() ) {}
#endif
template< class Y >
explicit QSharedPtr( Y* ptr ) : __base( ptr, LateDeleter<T>() ) {}
#ifdef Q_OS_WIN
QSharedPtr( std::nullptr_t ) : __base( nullptr, LateDeleter<T>() ) {}
#else
constexpr QSharedPtr( std::nullptr_t ) : __base( nullptr, LateDeleter<T>() ) {}
#endif
template< class Y >
QSharedPtr( const QSharedPtr<Y>& r ) : __base( r ) {}
QSharedPtr( QSharedPtr&& r ) : __base( std::forward<QSharedPtr>(r) ) {}
template< class Y >
QSharedPtr( QSharedPtr<Y>&& r ) : __base( std::forward<QSharedPtr<Y>>(r) ) {}
};
#ifdef Q_OS_WIN
// Hacky solution for VS2010
template<class _Ty, class T1>
QSharedPtr<_Ty> makeShared( T1&& arg1 ) { // make a shared_ptr
auto ptr = new _Ty( std::forward<T1>(arg1) );
return QSharedPtr<_Ty>( ptr );
}
#else
// Use proper variadic template arguments
template <class T, class... Args>
QSharedPtr<T> makeShared( Args&&... args ) {
auto ptr = new T( std::forward<Args>(args)... );
return QSharedPtr<T>( ptr );
}
#endif
While this seems to work great, I wonder whether there are further pitfalls, I have not thought about. Also would appreciate comments about this approach.