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. Lambda Evaluation in Signal/Slot Connection or QTimer
Forum Updated to NodeBB v4.3 + New Features

Lambda Evaluation in Signal/Slot Connection or QTimer

Scheduled Pinned Locked Moved Solved General and Desktop
8 Posts 3 Posters 829 Views 3 Watching
  • 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.
  • C Offline
    C Offline
    Crag_Hack
    wrote on last edited by Crag_Hack
    #1

    Hi I have a question about lambda evaluation in signal/slot connections or QTimer::singleShots. Sometimes you want to pass a variable allocated on the stack to a lambda and obviously you need the value to be passed at creation of the signal/slot connection or QTimer::singleShot or else the variable might not have a value any more and get overwritten with other data when the lambda is executed. Other times you want a variable to have it's value evaluated when the lambda is executed, say a boolean flag that could change from connection/timer creation to when the lambda is executed. My question is are signal/slot connections and QTimer:singleShots smart enough to tell when you want one behavior or the other? Do they always resort to one behavior and not the other depending on the capture type?
    Thanks!

    //Out of Scope Example
    void Class::function()
    {
        QString inputString;
        //user stores characters in string then timer prints string after string falls out of scope
        QTimer::singleShot(2000,[=]() { QDebug() << inputString; });
    }
    //In Scope Example
    bool jobDone is member of class
    void Class::function()
    {
        Connect(this,Class::closeWindow, [&]() { if (jobDone) window.close(); });
    }
    
    Pl45m4P 1 Reply Last reply
    0
    • C Crag_Hack

      Thanks guys appreciate the help. To clarify I was actually wondering am I correct about this: The lambdas capture the variables immediately upon creation and then are executed using those captures at the timeout of the timer or execution of the slot.

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #8

      @Crag_Hack
      Yes, as I wrote earlier ISTM you do understand lambdas and captures! :) Lambdas do their capture work where they are in the code, e.g. as a connect() statement is met to set up a signal/slot. The lambda-slot then uses those variables in its code when the slot is executed at a future time. With an = the variable's value is copied at connect()-time, so the slot will always its value as it was at that instant, while with an & only a reference to the variable, not its current value, is copied, so when accessed in the slot it will have its value as it is at that time. An &-captured variable must therefore still be in scope/alive when the lambda body executes, which is not required/not relevant for an =-captured one.

      1 Reply Last reply
      3
      • C Crag_Hack

        Hi I have a question about lambda evaluation in signal/slot connections or QTimer::singleShots. Sometimes you want to pass a variable allocated on the stack to a lambda and obviously you need the value to be passed at creation of the signal/slot connection or QTimer::singleShot or else the variable might not have a value any more and get overwritten with other data when the lambda is executed. Other times you want a variable to have it's value evaluated when the lambda is executed, say a boolean flag that could change from connection/timer creation to when the lambda is executed. My question is are signal/slot connections and QTimer:singleShots smart enough to tell when you want one behavior or the other? Do they always resort to one behavior and not the other depending on the capture type?
        Thanks!

        //Out of Scope Example
        void Class::function()
        {
            QString inputString;
            //user stores characters in string then timer prints string after string falls out of scope
            QTimer::singleShot(2000,[=]() { QDebug() << inputString; });
        }
        //In Scope Example
        bool jobDone is member of class
        void Class::function()
        {
            Connect(this,Class::closeWindow, [&]() { if (jobDone) window.close(); });
        }
        
        Pl45m4P Offline
        Pl45m4P Offline
        Pl45m4
        wrote on last edited by Pl45m4
        #2

        @Crag_Hack

        For the first one I'm not 100% sure, but the second one uses the value jobDone has, when the signal is emitted.
        As long as jobDone is a member, it's ok to use... using a local variable there will even throw a warning
        like
        captured local variable by reference might go out of scope before lambda is called [clazy-lambda-in-connect]

        Edit: If I'm not mistaken, the timer uses the value the variable had when the singleShot was called (started), as = copies the data.

         int localVar = 42;
         QTimer::singleShot(3000, [=](){ qDebug() << localVar; }); // value copied here
         localVar = 1337; // does not affect the timer (data already copied)
        

        This prints 42 and not 1337, even though localVar changed and when out of scope when the 3s delay was over.

        @Crag_Hack said in Lambda Evaluation in Signal/Slot Connection or QTimer:

        My question is are signal/slot connections and QTimer:singleShots smart enough to tell when you want one behavior or the other?

        How should the lambda know what your intentions are?!
        C++ does not prevent you from doing non-sense ;-)

        Capturing by reference - using either [&] or [&var] - in the first example results in undefined behavior and is non-sense, though.

        Btw:

        When using the a lambda affecting a QObject class as receiver or inside the lambda, it's recommended to set a context. Otherwise it might result in undefined behavior, as the lambda is not disconnected if the receiver or some object you manipulate inside the lambda is destroyed.


        If debugging is the process of removing software bugs, then programming must be the process of putting them in.

        ~E. W. Dijkstra

        JonBJ 1 Reply Last reply
        0
        • Pl45m4P Pl45m4

          @Crag_Hack

          For the first one I'm not 100% sure, but the second one uses the value jobDone has, when the signal is emitted.
          As long as jobDone is a member, it's ok to use... using a local variable there will even throw a warning
          like
          captured local variable by reference might go out of scope before lambda is called [clazy-lambda-in-connect]

          Edit: If I'm not mistaken, the timer uses the value the variable had when the singleShot was called (started), as = copies the data.

           int localVar = 42;
           QTimer::singleShot(3000, [=](){ qDebug() << localVar; }); // value copied here
           localVar = 1337; // does not affect the timer (data already copied)
          

          This prints 42 and not 1337, even though localVar changed and when out of scope when the 3s delay was over.

          @Crag_Hack said in Lambda Evaluation in Signal/Slot Connection or QTimer:

          My question is are signal/slot connections and QTimer:singleShots smart enough to tell when you want one behavior or the other?

          How should the lambda know what your intentions are?!
          C++ does not prevent you from doing non-sense ;-)

          Capturing by reference - using either [&] or [&var] - in the first example results in undefined behavior and is non-sense, though.

          Btw:

          When using the a lambda affecting a QObject class as receiver or inside the lambda, it's recommended to set a context. Otherwise it might result in undefined behavior, as the lambda is not disconnected if the receiver or some object you manipulate inside the lambda is destroyed.

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #3

          @Pl45m4 said in Lambda Evaluation in Signal/Slot Connection or QTimer:

          Capturing by reference - using either [&] or [&var] - in the first example is totally fine (non-sense, though), but will result in 0/no data, every time.

          Um, no, it will/should result in undefined behaviour if you are "lucky" or a crash if you are "unlucky" (or perhaps the luck is the other way round, depends on your POV!). QString inputString is a local variable on the stack, and it goes out of scope and is destroyed as soon as function() exits after setting up the timer. Capturing it by reference via & to the lambda will mean when the slot is executed it tries to access some stack address which is no longer valid. Actually I see you quoted a possible compiler error message for this, that would/should happen for the first example if OP put & instead of = there.

          @Crag_Hack
          Not sure what/why you are asking here. You seem to understand = versus & (and @Pl45m4's clarifications are correct), you seem to know when to use which, so that's it. It's not Qt/signal/slot which knows anything "smart", it's you as programmer who have to pass the right one!

          Pl45m4P 1 Reply Last reply
          1
          • JonBJ JonB

            @Pl45m4 said in Lambda Evaluation in Signal/Slot Connection or QTimer:

            Capturing by reference - using either [&] or [&var] - in the first example is totally fine (non-sense, though), but will result in 0/no data, every time.

            Um, no, it will/should result in undefined behaviour if you are "lucky" or a crash if you are "unlucky" (or perhaps the luck is the other way round, depends on your POV!). QString inputString is a local variable on the stack, and it goes out of scope and is destroyed as soon as function() exits after setting up the timer. Capturing it by reference via & to the lambda will mean when the slot is executed it tries to access some stack address which is no longer valid. Actually I see you quoted a possible compiler error message for this, that would/should happen for the first example if OP put & instead of = there.

            @Crag_Hack
            Not sure what/why you are asking here. You seem to understand = versus & (and @Pl45m4's clarifications are correct), you seem to know when to use which, so that's it. It's not Qt/signal/slot which knows anything "smart", it's you as programmer who have to pass the right one!

            Pl45m4P Offline
            Pl45m4P Offline
            Pl45m4
            wrote on last edited by
            #4

            @JonB said in Lambda Evaluation in Signal/Slot Connection or QTimer:

            Um, no, it will/should result in undefined behaviour if you are "lucky" or a crash if you are "unlucky" (or perhaps the luck is the other way round, depends on your POV!). QString inputString is a local variable on the stack, and it goes out of scope and is destroyed as soon as function() exits after setting up the timer

            Yes I know but I even tried it, and got 0 for ints and "" for captured strings consequently.
            Maybe I was just lucky :D
            The behavior is still undefined and not the right way, as I've said before :)


            If debugging is the process of removing software bugs, then programming must be the process of putting them in.

            ~E. W. Dijkstra

            JonBJ 1 Reply Last reply
            0
            • Pl45m4P Pl45m4

              @JonB said in Lambda Evaluation in Signal/Slot Connection or QTimer:

              Um, no, it will/should result in undefined behaviour if you are "lucky" or a crash if you are "unlucky" (or perhaps the luck is the other way round, depends on your POV!). QString inputString is a local variable on the stack, and it goes out of scope and is destroyed as soon as function() exits after setting up the timer

              Yes I know but I even tried it, and got 0 for ints and "" for captured strings consequently.
              Maybe I was just lucky :D
              The behavior is still undefined and not the right way, as I've said before :)

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by JonB
              #5

              @Pl45m4
              I don't mean to drag this on, but you wrote

              Capturing by reference - using either [&] or [&var] - in the first example is totally fine (non-sense, though), but will result in 0/no data, every time.

              But it isn't "totally fine" for anyone reading, it's undefined and bad. If you got 0 or empty string that is just whatever happened to be on the stack at the original address in your case in your app on your machine. I might not, you might not tomorrow. Either it's "fine" or it's "undefined and bad".

              Pl45m4P 1 Reply Last reply
              0
              • JonBJ JonB

                @Pl45m4
                I don't mean to drag this on, but you wrote

                Capturing by reference - using either [&] or [&var] - in the first example is totally fine (non-sense, though), but will result in 0/no data, every time.

                But it isn't "totally fine" for anyone reading, it's undefined and bad. If you got 0 or empty string that is just whatever happened to be on the stack at the original address in your case in your app on your machine. I might not, you might not tomorrow. Either it's "fine" or it's "undefined and bad".

                Pl45m4P Offline
                Pl45m4P Offline
                Pl45m4
                wrote on last edited by
                #6

                @JonB

                ok, corrected :))


                If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                ~E. W. Dijkstra

                1 Reply Last reply
                1
                • C Offline
                  C Offline
                  Crag_Hack
                  wrote on last edited by
                  #7

                  Thanks guys appreciate the help. To clarify I was actually wondering am I correct about this: The lambdas capture the variables immediately upon creation and then are executed using those captures at the timeout of the timer or execution of the slot.

                  JonBJ 1 Reply Last reply
                  0
                  • C Crag_Hack

                    Thanks guys appreciate the help. To clarify I was actually wondering am I correct about this: The lambdas capture the variables immediately upon creation and then are executed using those captures at the timeout of the timer or execution of the slot.

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by
                    #8

                    @Crag_Hack
                    Yes, as I wrote earlier ISTM you do understand lambdas and captures! :) Lambdas do their capture work where they are in the code, e.g. as a connect() statement is met to set up a signal/slot. The lambda-slot then uses those variables in its code when the slot is executed at a future time. With an = the variable's value is copied at connect()-time, so the slot will always its value as it was at that instant, while with an & only a reference to the variable, not its current value, is copied, so when accessed in the slot it will have its value as it is at that time. An &-captured variable must therefore still be in scope/alive when the lambda body executes, which is not required/not relevant for an =-captured one.

                    1 Reply Last reply
                    3
                    • C Crag_Hack has marked this topic as solved on

                    • Login

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