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. Destroy the signal/slot connection when the slot receives the signal
Qt 6.11 is out! See what's new in the release blog

Destroy the signal/slot connection when the slot receives the signal

Scheduled Pinned Locked Moved Unsolved General and Desktop
14 Posts 6 Posters 3.5k 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.
  • J Offline
    J Offline
    johnyang
    wrote on last edited by
    #1

    Is there a way to destroy the signal/slot connection once the signal has been triggered so this connection only gets triggered once? I came across the following code:
    std::unique_ptr<QObject> context{ new QObject };
    QObject* pcontext = context.get();
    auto connection =
    connect(this,
    &SenderClass::send,
    pcontext,
    this, context = std::move(context) mutable
    {
    context.reset();
    // do something when received the signal
    });

    When context is reset, the connection is destroyed. Is this a bad practice? It seems to be working alright but some developer thinks it is dangerous because pcontext owns that lambda function which destroys itself.

    or is there another way to achieve the same behaviour?

    jsulmJ J.HilkJ 2 Replies Last reply
    0
    • J johnyang

      Is there a way to destroy the signal/slot connection once the signal has been triggered so this connection only gets triggered once? I came across the following code:
      std::unique_ptr<QObject> context{ new QObject };
      QObject* pcontext = context.get();
      auto connection =
      connect(this,
      &SenderClass::send,
      pcontext,
      this, context = std::move(context) mutable
      {
      context.reset();
      // do something when received the signal
      });

      When context is reset, the connection is destroyed. Is this a bad practice? It seems to be working alright but some developer thinks it is dangerous because pcontext owns that lambda function which destroys itself.

      or is there another way to achieve the same behaviour?

      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @johnyang Please format your code properly.
      You can simply call disconnect() (https://doc.qt.io/qt-6/qobject.html#disconnect).

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      J 1 Reply Last reply
      3
      • J johnyang

        Is there a way to destroy the signal/slot connection once the signal has been triggered so this connection only gets triggered once? I came across the following code:
        std::unique_ptr<QObject> context{ new QObject };
        QObject* pcontext = context.get();
        auto connection =
        connect(this,
        &SenderClass::send,
        pcontext,
        this, context = std::move(context) mutable
        {
        context.reset();
        // do something when received the signal
        });

        When context is reset, the connection is destroyed. Is this a bad practice? It seems to be working alright but some developer thinks it is dangerous because pcontext owns that lambda function which destroys itself.

        or is there another way to achieve the same behaviour?

        J.HilkJ Offline
        J.HilkJ Offline
        J.Hilk
        Moderators
        wrote on last edited by
        #3

        @johnyang I don't really see the reason why you would want a single shot connection?

        Why don't you simply call the function directly?

        That said, @jsulm is correct, calling disconnect is probably the correct approach. However it can be tricky and I would suggest using QMetaObject::Connection explicitly

        QMetaObject::Connection conn;
        conn = QObject::connect(sender, &Sender::signal, [=]() mutable {
            // Slot code to be executed
            // ...
        
            // Disconnect the connection
            QObject::disconnect(conn);
        });
        

        at least you don't end up with unnecessary object creations/allocations


        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


        Q: What's that?
        A: It's blue light.
        Q: What does it do?
        A: It turns blue.

        J 1 Reply Last reply
        2
        • jsulmJ jsulm

          @johnyang Please format your code properly.
          You can simply call disconnect() (https://doc.qt.io/qt-6/qobject.html#disconnect).

          J Offline
          J Offline
          johnyang
          wrote on last edited by
          #4

          @jsulm Somehow it won't let me post code with this error "Post content was flagged as spam by Akismet.com". However I was using QT5. But that seems to point me to the right direction.

          1 Reply Last reply
          0
          • J.HilkJ J.Hilk

            @johnyang I don't really see the reason why you would want a single shot connection?

            Why don't you simply call the function directly?

            That said, @jsulm is correct, calling disconnect is probably the correct approach. However it can be tricky and I would suggest using QMetaObject::Connection explicitly

            QMetaObject::Connection conn;
            conn = QObject::connect(sender, &Sender::signal, [=]() mutable {
                // Slot code to be executed
                // ...
            
                // Disconnect the connection
                QObject::disconnect(conn);
            });
            

            at least you don't end up with unnecessary object creations/allocations

            J Offline
            J Offline
            johnyang
            wrote on last edited by
            #5

            @J-Hilk I'm trying to implement a single shot connection waiting for an asynchronous response from http server. I'm curious if the connection in your code will be cleared when it gets out of scope?
            Should I do something like this instead:

            QMetaObject::Connection * const connection = new QMetaObject::Connection;
            *connection = connect(sender, &Sender::signal, [this, connection](){
            
                QObject::disconnect(*connection);
                delete connection;
            });
            
            J.HilkJ 1 Reply Last reply
            0
            • J johnyang

              @J-Hilk I'm trying to implement a single shot connection waiting for an asynchronous response from http server. I'm curious if the connection in your code will be cleared when it gets out of scope?
              Should I do something like this instead:

              QMetaObject::Connection * const connection = new QMetaObject::Connection;
              *connection = connect(sender, &Sender::signal, [this, connection](){
              
                  QObject::disconnect(*connection);
                  delete connection;
              });
              
              J.HilkJ Offline
              J.HilkJ Offline
              J.Hilk
              Moderators
              wrote on last edited by
              #6

              @johnyang thats not needed, the framework manages the lambda internally. In this case the connection and lambda will be valid as long as the sender instance exists or disconnect was called.

              And stuff captured by lambdas does not go out of scope, as long as you don't explicitly capture by reference. As it makes its own copy.


              Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


              Q: What's that?
              A: It's blue light.
              Q: What does it do?
              A: It turns blue.

              1 Reply Last reply
              4
              • Christian EhrlicherC Offline
                Christian EhrlicherC Offline
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by
                #7

                There is also a single shot connection type...

                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
                8
                • GrecKoG Offline
                  GrecKoG Offline
                  GrecKo
                  Qt Champions 2018
                  wrote on last edited by
                  #8

                  @johnyang Is Sender a long lived object that sends signal multiple times?
                  If not it might not be necessary to disconnect from it, similar to how we usually connect a lambda to QNetworkReply::finished without disconnecting after.
                  And like Christian just said there's Qt::SingleShotConnection as parameter of QObject::connect since Qt 6.0

                  J.HilkJ J 2 Replies Last reply
                  2
                  • GrecKoG GrecKo

                    @johnyang Is Sender a long lived object that sends signal multiple times?
                    If not it might not be necessary to disconnect from it, similar to how we usually connect a lambda to QNetworkReply::finished without disconnecting after.
                    And like Christian just said there's Qt::SingleShotConnection as parameter of QObject::connect since Qt 6.0

                    J.HilkJ Offline
                    J.HilkJ Offline
                    J.Hilk
                    Moderators
                    wrote on last edited by
                    #9

                    @GrecKo said in Destroy the signal/slot connection when the slot receives the signal:

                    Qt::SingleShotConnection as parameter of QObject::connect since Qt 6.0

                    Look at that!

                    alt text


                    Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                    Q: What's that?
                    A: It's blue light.
                    Q: What does it do?
                    A: It turns blue.

                    J 1 Reply Last reply
                    3
                    • J.HilkJ J.Hilk

                      @GrecKo said in Destroy the signal/slot connection when the slot receives the signal:

                      Qt::SingleShotConnection as parameter of QObject::connect since Qt 6.0

                      Look at that!

                      alt text

                      J Offline
                      J Offline
                      johnyang
                      wrote on last edited by
                      #10

                      @J-Hilk Unfortunately I'm still on Qt5 at the moment. I would love to get onto Qt6 soon. I have another question about using the disconnect approach. I have the following scenario:

                      QMetaObject::Connection * const connection = new QMetaObject::Connection;
                      *connection = connect(sender, &Sender::signal, [this, connection](){
                      
                          QObject::disconnect(*connection);
                          delete connection;
                          
                          // Some function that also sends out Sender::signal
                          Function();
                      
                      });
                      

                      Function() also sends out Sender::signal at the end. The above code seems to be working fine that the lambda function does not get triggered. However if I do the following, the lambda function does get triggered one more time (which is not what I want):

                      QMetaObject::Connection conn;
                      conn = QObject::connect(sender, &Sender::signal, [=]() {
                          // Disconnect the connection
                          QObject::disconnect(conn);
                      
                          // Some function that also sends out Sender::signal
                          Function();
                      });
                      

                      Is it alright to do what I did in the code above?

                      1 Reply Last reply
                      0
                      • GrecKoG GrecKo

                        @johnyang Is Sender a long lived object that sends signal multiple times?
                        If not it might not be necessary to disconnect from it, similar to how we usually connect a lambda to QNetworkReply::finished without disconnecting after.
                        And like Christian just said there's Qt::SingleShotConnection as parameter of QObject::connect since Qt 6.0

                        J Offline
                        J Offline
                        johnyang
                        wrote on last edited by johnyang
                        #11

                        @GrecKo Sender is a long lived object but I only want it to take place once for a logic reason. I am still on Qt5 at the moment so I can't use Qt::SingleShotConnection. However in my example code with unique pointer, is it a bad practice to reset context in the lambda function because it is owned by context?

                        QObject* pcontext = context.get();
                        connect(this, &SenderClass::send, pcontext, [this, context = std::move(context)] mutable
                        {
                            context.reset();
                            // do something when received the signal
                            Function();
                        });
                        
                        1 Reply Last reply
                        0
                        • J Offline
                          J Offline
                          johnyang
                          wrote on last edited by
                          #12

                          At the moment, the suggested code in https://www.kdab.com/single-shot-connections/ seems to work perfectly so far:

                          auto connection = std::make_unique<QMetaObject::Connection>();
                          auto connectionPtr = connection.get();
                          
                          auto singleShot = [receiver, connection = std::move(connection)](parameters) {
                            QObject::disconnect(*connection);
                            receiver->slot(parameters);
                          };
                          
                          *connectionPtr = connect(sender, &Sender::signal, receiver, std::move(singleShot)));
                          
                          1 Reply Last reply
                          0
                          • S Offline
                            S Offline
                            smada
                            wrote on last edited by
                            #13

                            This is my concern about the above:

                            int a = 5;
                            int b = 6;
                            auto connection = std::make_unique<QMetaObject::Connection>();
                            auto connectionPtr = connection.get();
                            
                            auto singleShot = [a, b, connection = std::move(connection)](parameters) {
                              QObject::disconnect(*connection);
                            
                              // Is the captured variable 'a' and 'b' still valid here? Or has this lambda been destroyed by
                              // the call to disconnect and thus 'a' and 'b' is no longer valid?
                              doSomethingWith(a, b);
                            };
                            
                            *connectionPtr = connect(sender, &Sender::signal, receiver, std::move(singleShot)));
                            

                            If the latter is true, (i.e. calling disconnect results in the lambda being destroyed) then we can no longer assume 'a' and 'b' are valid values. This could result in doSomethingWith(a, b) crashing, or worse not crashing because something else has occupied the address space of 'a' or 'b' and no longer represents the original value.

                            What I am ultimately asking here is, when does the lambda get destroyed after a disconnect is called?

                            1 Reply Last reply
                            0
                            • S Offline
                              S Offline
                              smada
                              wrote on last edited by
                              #14

                              I am just wondering if anyone has a answer of this?

                              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