Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QSharedPointer in destructed signal parameter deletes object which has other QSharedPointer

QSharedPointer in destructed signal parameter deletes object which has other QSharedPointer

Scheduled Pinned Locked Moved Unsolved General and Desktop
4 Posts 3 Posters 920 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • F Offline
    F Offline
    fatih.erol
    wrote on last edited by fatih.erol
    #1

    Hello.

    Could someone explain or point me to a best practices guide for proper use of QSharedPointers as parameters to constructors and signals?

    I have an example code below:

    • In Manager::start function, I emit Object::start, which calls the connected Object::onStart slot.
    • In Object::onStart slot, I emit Object::started signal with Event parameter (that has ObjectSharedPointer), which calls the connected Manager::onStarted slot.
    • After Manager::onStarted slot, the Event parameter naturally gets deleted when it is out of scope.
    • This, in turn, deletes the ObjectSharedPointer member of Event. However, this deletes the object pointed to by the shared pointer, although there is still a shared pointer in Manager::_objects vector.
    • On exit (Ctrl+C), the destructor of the shared pointer vector Manager::_objects causes a crash in this case.

    Is this related to passing const& to the shared pointer in Event constructor?
    How do we properly construct Event and emit a signal with it?

    (Please ignore cosmetic issues)

    output

    "@0x00000000011be2d0 Manager::Manager()"
    "@0x00000000011c0460 Object::Object( Object 0 )"
    "@0x00000000011bff90 Object::Object( Object 1 )"
    "@0x00000000011be2d0 Manager::start()"
    "@0x00000000011c0460 Object::onStart( Object 0 )"
    "@0x00000000011c0460 Object::onStart::emit( Event( Object 0 ) )"
    "@0x00007fffc64d4ff0 Event::Event( Object 0 )"
    "@0x00000000011be2d0 Manager::onStarted( Event@0x00007fffc64d4ff0( Object 0 ) )"
    "@0x00007fffc64d4ff0 Event::~Event( Object 0 )"
    "@0x00000000011c0460 Object::~Object( Object 0 )"
    "@0x00000000011bff90 Object::onStart( Object 1 )"
    "@0x00000000011bff90 Object::onStart::emit( Event( Object 1 ) )"
    "@0x00007fffc64d4ff0 Event::Event( Object 1 )"
    "@0x00000000011be2d0 Manager::onStarted( Event@0x00007fffc64d4ff0( Object 1 ) )"
    "@0x00007fffc64d4ff0 Event::~Event( Object 1 )"
    "@0x00000000011bff90 Object::~Object( Object 1 )"
    ^C
    "@0x00000000011be2d0 Manager::~Manager()"
    Segmentation fault (core dumped)
    

    test.hpp

    #include <QtCore/QSharedPointer>
    #include <QtCore/QVector>
    
    
    class Object;
    typedef QSharedPointer<Object> ObjectSharedPointer;
    typedef QVector<ObjectSharedPointer> ObjectVector;
    
    
    class Event
    {
    public:
        ObjectSharedPointer _object;
    
    public:
        Event( const ObjectSharedPointer &object = nullptr );
        ~Event();
    };
    Q_DECLARE_METATYPE( Event )
    
    
    class Object : public QObject
    {
        Q_OBJECT
    
    public:
        QString _name;
    
    public:
        Object( const QString &name );
        ~Object();
    
    signals:
        void start();
        void started( const Event &event );
    
    private slots:
        void onStart();
    };
    
    
    class Manager : public QObject
    {
        Q_OBJECT
    
    public:
        ObjectVector _objects;
    
    public:
        Manager();
        ~Manager();
    
        void start();
    
    private slots:
        void onStarted( const Event &event );
    };
    

    test.cpp

    #include <csignal>
    #include <cstdlib>
    #include <QtCore/QDebug>
    #include <QtCore/QCoreApplication>
    #include "test.hpp"
    
    template <typename T>
    QString getPointer( const T *object )
    {
        return QString( "0x%1" ).arg( reinterpret_cast<unsigned long long int>( object ), sizeof( T* ) * 2, 16, QChar( '0' ) );
    }
    
    QString getObjectName( const ObjectSharedPointer &object ) { return QString( object.isNull() ? "nullptr" : object->_name ); } 
    
    Event::Event( const ObjectSharedPointer &object ) : _object( object ) { qDebug() << QString( "@%1 %2( %3 )" ).arg( getPointer( this ) ).arg( "Event::Event" ).arg( getObjectName( _object ) ); }
    Event::~Event() { qDebug() << QString( "@%1 %2( %3 )" ).arg( getPointer( this ) ).arg( "Event::~Event" ).arg( getObjectName( _object ) ); }
    
    Object::Object( const QString &name ) : _name( name )
    {
        qDebug() << QString( "@%1 %2( %3 )" ).arg( getPointer( this ) ).arg( "Object::Object" ).arg( _name );
        QObject::connect( this, &Object::start, this, &Object::onStart );
    }
    Object::~Object()
    {
        qDebug() << QString( "@%1 %2( %3 )" ).arg( getPointer( this ) ).arg( "Object::~Object" ).arg( _name );
    }
    void Object::onStart()
    {
        qDebug() << QString( "@%1 %2( %3 )" ).arg( getPointer( this ) ).arg( "Object::onStart" ).arg( _name );
        qDebug() << QString( "@%1 %2( Event( %3 ) )" ).arg( getPointer( this ) ).arg( "Object::onStart::emit" ).arg( _name );
        emit started( Event( ObjectSharedPointer( this ) ) );
    }
    
    Manager::Manager()
    {
        qDebug() << QString( "@%1 %2()" ).arg( getPointer( this ) ).arg( "Manager::Manager" );
    
        qRegisterMetaType<Event>( "Event" );
        for ( int i = 0; i < 2; ++i )
        {
            Object *object = new Object( QString( "Object %1" ).arg( _objects.size() ) );
            QObject::connect( object, &Object::started, this, &Manager::onStarted );
            _objects.append( ObjectSharedPointer( object ) );
        }
    }
    Manager::~Manager() { qDebug() << QString( "@%1 %2()" ).arg( getPointer( this ) ).arg( "Manager::~Manager" ); }
    void Manager::start() { qDebug() << QString( "@%1 %2()" ).arg( getPointer( this ) ).arg( "Manager::start" ); for ( ObjectSharedPointer &object : _objects ) { emit object->start(); } }
    void Manager::onStarted( const Event &event )
    {
        qDebug() << QString( "@%1 %2( Event@%3( %4 ) )" ).arg( getPointer( this ) ).arg( "Manager::onStarted" ).arg( getPointer( &event ) ).arg( getObjectName( event._object ) );
    }
    
    QCoreApplication *application;
    Manager *manager;
    
    void onSignal( int signal )
    {
        qDebug() << "";
        delete manager;
        application->quit();
    }
    
    int main( int argc, char **argv )
    {
        ::signal( SIGINT, onSignal );
        ::signal( SIGTERM, onSignal );
    
        application = new QCoreApplication( argc, argv );
        manager = new Manager();
        manager->start();
        return application->exec();
    }
    
    kshegunovK 1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @fatih.erol said in QSharedPointer in destructed signal parameter deletes object which has other QSharedPointer:

      emit started( Event( ObjectSharedPointer( this ) ) );

      You're creating a new QSharedPointer here which gets destroyed after the signal is done so the object gets destroyed.

      And why do you create a QApplication instance on the heap?

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      1 Reply Last reply
      5
      • F fatih.erol

        Hello.

        Could someone explain or point me to a best practices guide for proper use of QSharedPointers as parameters to constructors and signals?

        I have an example code below:

        • In Manager::start function, I emit Object::start, which calls the connected Object::onStart slot.
        • In Object::onStart slot, I emit Object::started signal with Event parameter (that has ObjectSharedPointer), which calls the connected Manager::onStarted slot.
        • After Manager::onStarted slot, the Event parameter naturally gets deleted when it is out of scope.
        • This, in turn, deletes the ObjectSharedPointer member of Event. However, this deletes the object pointed to by the shared pointer, although there is still a shared pointer in Manager::_objects vector.
        • On exit (Ctrl+C), the destructor of the shared pointer vector Manager::_objects causes a crash in this case.

        Is this related to passing const& to the shared pointer in Event constructor?
        How do we properly construct Event and emit a signal with it?

        (Please ignore cosmetic issues)

        output

        "@0x00000000011be2d0 Manager::Manager()"
        "@0x00000000011c0460 Object::Object( Object 0 )"
        "@0x00000000011bff90 Object::Object( Object 1 )"
        "@0x00000000011be2d0 Manager::start()"
        "@0x00000000011c0460 Object::onStart( Object 0 )"
        "@0x00000000011c0460 Object::onStart::emit( Event( Object 0 ) )"
        "@0x00007fffc64d4ff0 Event::Event( Object 0 )"
        "@0x00000000011be2d0 Manager::onStarted( Event@0x00007fffc64d4ff0( Object 0 ) )"
        "@0x00007fffc64d4ff0 Event::~Event( Object 0 )"
        "@0x00000000011c0460 Object::~Object( Object 0 )"
        "@0x00000000011bff90 Object::onStart( Object 1 )"
        "@0x00000000011bff90 Object::onStart::emit( Event( Object 1 ) )"
        "@0x00007fffc64d4ff0 Event::Event( Object 1 )"
        "@0x00000000011be2d0 Manager::onStarted( Event@0x00007fffc64d4ff0( Object 1 ) )"
        "@0x00007fffc64d4ff0 Event::~Event( Object 1 )"
        "@0x00000000011bff90 Object::~Object( Object 1 )"
        ^C
        "@0x00000000011be2d0 Manager::~Manager()"
        Segmentation fault (core dumped)
        

        test.hpp

        #include <QtCore/QSharedPointer>
        #include <QtCore/QVector>
        
        
        class Object;
        typedef QSharedPointer<Object> ObjectSharedPointer;
        typedef QVector<ObjectSharedPointer> ObjectVector;
        
        
        class Event
        {
        public:
            ObjectSharedPointer _object;
        
        public:
            Event( const ObjectSharedPointer &object = nullptr );
            ~Event();
        };
        Q_DECLARE_METATYPE( Event )
        
        
        class Object : public QObject
        {
            Q_OBJECT
        
        public:
            QString _name;
        
        public:
            Object( const QString &name );
            ~Object();
        
        signals:
            void start();
            void started( const Event &event );
        
        private slots:
            void onStart();
        };
        
        
        class Manager : public QObject
        {
            Q_OBJECT
        
        public:
            ObjectVector _objects;
        
        public:
            Manager();
            ~Manager();
        
            void start();
        
        private slots:
            void onStarted( const Event &event );
        };
        

        test.cpp

        #include <csignal>
        #include <cstdlib>
        #include <QtCore/QDebug>
        #include <QtCore/QCoreApplication>
        #include "test.hpp"
        
        template <typename T>
        QString getPointer( const T *object )
        {
            return QString( "0x%1" ).arg( reinterpret_cast<unsigned long long int>( object ), sizeof( T* ) * 2, 16, QChar( '0' ) );
        }
        
        QString getObjectName( const ObjectSharedPointer &object ) { return QString( object.isNull() ? "nullptr" : object->_name ); } 
        
        Event::Event( const ObjectSharedPointer &object ) : _object( object ) { qDebug() << QString( "@%1 %2( %3 )" ).arg( getPointer( this ) ).arg( "Event::Event" ).arg( getObjectName( _object ) ); }
        Event::~Event() { qDebug() << QString( "@%1 %2( %3 )" ).arg( getPointer( this ) ).arg( "Event::~Event" ).arg( getObjectName( _object ) ); }
        
        Object::Object( const QString &name ) : _name( name )
        {
            qDebug() << QString( "@%1 %2( %3 )" ).arg( getPointer( this ) ).arg( "Object::Object" ).arg( _name );
            QObject::connect( this, &Object::start, this, &Object::onStart );
        }
        Object::~Object()
        {
            qDebug() << QString( "@%1 %2( %3 )" ).arg( getPointer( this ) ).arg( "Object::~Object" ).arg( _name );
        }
        void Object::onStart()
        {
            qDebug() << QString( "@%1 %2( %3 )" ).arg( getPointer( this ) ).arg( "Object::onStart" ).arg( _name );
            qDebug() << QString( "@%1 %2( Event( %3 ) )" ).arg( getPointer( this ) ).arg( "Object::onStart::emit" ).arg( _name );
            emit started( Event( ObjectSharedPointer( this ) ) );
        }
        
        Manager::Manager()
        {
            qDebug() << QString( "@%1 %2()" ).arg( getPointer( this ) ).arg( "Manager::Manager" );
        
            qRegisterMetaType<Event>( "Event" );
            for ( int i = 0; i < 2; ++i )
            {
                Object *object = new Object( QString( "Object %1" ).arg( _objects.size() ) );
                QObject::connect( object, &Object::started, this, &Manager::onStarted );
                _objects.append( ObjectSharedPointer( object ) );
            }
        }
        Manager::~Manager() { qDebug() << QString( "@%1 %2()" ).arg( getPointer( this ) ).arg( "Manager::~Manager" ); }
        void Manager::start() { qDebug() << QString( "@%1 %2()" ).arg( getPointer( this ) ).arg( "Manager::start" ); for ( ObjectSharedPointer &object : _objects ) { emit object->start(); } }
        void Manager::onStarted( const Event &event )
        {
            qDebug() << QString( "@%1 %2( Event@%3( %4 ) )" ).arg( getPointer( this ) ).arg( "Manager::onStarted" ).arg( getPointer( &event ) ).arg( getObjectName( event._object ) );
        }
        
        QCoreApplication *application;
        Manager *manager;
        
        void onSignal( int signal )
        {
            qDebug() << "";
            delete manager;
            application->quit();
        }
        
        int main( int argc, char **argv )
        {
            ::signal( SIGINT, onSignal );
            ::signal( SIGTERM, onSignal );
        
            application = new QCoreApplication( argc, argv );
            manager = new Manager();
            manager->start();
            return application->exec();
        }
        
        kshegunovK Offline
        kshegunovK Offline
        kshegunov
        Moderators
        wrote on last edited by
        #3

        And why would you hold a QObject in a shared pointer to begin with? You're asking for trouble ...

        Read and abide by the Qt Code of Conduct

        1 Reply Last reply
        2
        • F Offline
          F Offline
          fatih.erol
          wrote on last edited by
          #4

          Thank you. I should have read QEnableSharedFromThis documentation.

          You can inherit this class when you need to create a QSharedPointer from any instance of a class; for instance, from within the object itself. The key point is that the technique of just returning QSharedPointer<T>(this) can not be used, because this winds up creating multiple distinct QSharedPointer objects with separate reference counts. For this reason you must never create more than one QSharedPointer from the same raw pointer.
          

          I guess, the pointer was being smart, but I was not, by initiating one from 'this' pointer in signal. That does not really convey ownership semantics particularly. I must have assumed the references were counted globally based on shared pointer objects pointing to the raw pointer value. Event member could be a raw pointer instead.

          The example was carved roughly to test the issue. No particular reason QCoreApplication was a pointer; I pulled it out of main to handle 'Ctrl+C', although the method might go against "You can't call Qt functions from Unix signal handlers." Also, I wanted to explicitly delete Manager on 'Ctrl+C'.

          QSharedPointer documentation does not have any warning about pointing to QObject-derived classes. Actually, it does so in examples setting custom deleter to Object::deleteLater. I guess, it can conflict with Qt's parent/child mechanism.

          1 Reply Last reply
          0

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved