1

I want to pass a QString into a lambda slot-function to modify it further. Unfortunately the QString goes out of scope before reaching the slot, so I cannot append text. How can I ensure that the QString is not running out of scope to process it inside the lambda? A class member is no option for me.

// main.cpp
#include <QObject>
#include <qtclass.h>

int main(int argc, char* argv[])
{
    QtClass q;
    q.foo();
    emit q.bar();
}
// qtclass.h
#include <QObject>

class QtClass : public QObject
{
    Q_OBJECT

public:
    void foo()
    {
        QString msg = "Hello"; // the string is being modified depending on different situations
        if (boolFunc1())
           msg += " qt";
        if (!boolFunc2())
           msg += " 123";
        QObject::connect(this, &QtClass::bar, this, [&msg]()
            {
                msg.append(" World"); // access violation reading position, msg is out of scope
            });
    };

signals:
    void bar();
};
7
  • Allocate it Dynamically? Commented Nov 7 at 7:58
  • 5
    It's not clear to me what you want to achieve. Currently, it looks like you could simply declare the string in the lambda. I don't understand what you mean by a class member is no option for me. What's the use case? Commented Nov 7 at 8:01
  • @Erel I am writing text to the string before invoking the slot-function as shown in the example. In the slot I want to append more text to pass the string around the application. Commented Nov 7 at 8:02
  • 2
    I meant I don't quite grasp how you intend to pass the string around if it's declared in a function scope. If it needs to live for as long as QtClass leaves, then it should be either a static member of QtClass or a non-static member of an instance of QtClass. Commented Nov 7 at 8:06
  • 2
    @Me3nTaL The question you have to ask yourself first is: What is the purpose of msg ? Because it is locally defined inside foo() so mutating it here is of no use because it is inaccessible outside of foo(). So first defined how msg is meant to be used, who is supposed to read/write into it, and so on, and I bet the solution to your issue will appear as an evidence. Commented Nov 7 at 8:43

3 Answers 3

4

Since the lambda outlives the local variable msg, then the variable should be copied (removing &):

    QString msg = "Hello";
    msg += " qt";
    QObject::connect(this, &QtClass::bar, this, [msg]
        {
            msg.append(" World");
        });

If msg is not used after these statements, then the variable can be moved:

    QString msg = "Hello";
    msg += " qt";
    QObject::connect(this, &QtClass::bar, this, [msg = std::move(msg)]
        {
            msg.append(" World");
        });

msg.append(" World") seems to modify msg. Hence, the code does not compile, the lambda must be mutable:

[msg = std::move(msg)]() mutable
Sign up to request clarification or add additional context in comments.

Comments

1

It can be achieved by using a lambda initializer expression

[msg = QString("Hello")]()
{
    msg.append(" World");
}

2 Comments

The lambda has to be mutable, but that's what I would have done too.
I cannot initialize the QString with just one value. I am filling different text to it before invoking the slot.
1

Other answer provided quick fix without thinking about code intent. It just fixes the crash.

Yes problem is that live time of msg ends before lambda is used, but creating a copy of this variable doesn't seem as proper program logic. Modifying copy of msg without having access to it is useless. If new calculated value can't be used, then there is no reason to calculate it.

IMO proper fix is to introduce a filed of QtClass and capture this or this specific field, so this value updated by lambda is accessible by other parts of the code.

class QtClass : public QObject
{
    Q_OBJECT

    QString msg = "Hello";
public:
    void foo()
    {
        if (boolFunc1())
           msg += " qt";
        if (!boolFunc2())
           msg += " 123";
        QObject::connect(this, &QtClass::bar, this, [&msg]()
            {
                msg.append(" World");
            });
    };

    void logMsg() const {
       qDebug() << msg;
    }
signals:
    void bar();
};

Now msg will live as long as instance of QtClass lives. This means when signal bar is emitted we have warranty that msg exists adn we can use this value in other prts of the code.

Disclaimer:
This code has more strange things which seems wrong or unnecessary, but this is out of the question scope.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.