【问题标题】:Share object between two lambdas在两个 lambda 之间共享对象
【发布时间】:2019-04-10 17:13:23
【问题描述】:

我正在尝试使用 shared_ptr 在 lambdas 之间共享相同的对象(在我的例子中是一个字符串):

auto fileToLoad = make_shared<string>();
    StartAsync(
        [=]()
    {

        QDir dir(dirPath.c_str());
        QString fileExtension(fileExt.c_str());

        for (int i = 0; i < 150; i++)
        {
            auto files = dir.entryList(QStringList() << fileExtension << fileExtension.toUpper(), QDir::Files);
            if (!files.empty())
            {
                //fileToLoad.reset(new string(files.first().toUtf8().constData()));
                fileToLoad = make_shared<string>(files.first().toUtf8().constData());
                break;
            }

            this_thread::sleep_for(chrono::milliseconds(200));
        }
    },
        [=]()
    {
        if (fileToLoad == nullptr)
        {
            DisplayMessage("Timeout reached");
        }
        else
        {
            doFunc(*fileToLoad);
        }
    });

经过多次尝试,我仍然无法让它按我的意愿工作:将 fileToLoad 存储在第一个 lambda 中并在第二个中使用它。或者由于限定符 (const) 导致编译失败,或者编译但 'fileToLoad' 仍然为空。

如您所见,我试图通知文件是否出现在文件夹中,使用 StartAsync 函数,该函数需要 2 个 lambda(该函数基本上创建 QObjects 并将它们移动到后台线程,然后在信号和插槽之间建立一些连接)。

编辑:

StartAsync:接受一个任务的 lambda(冗长的工作)和一个发布任务的 lambda(UI 更新)

void MainWidget::StartAsync(function<void()> func, function<void()> postTask)
{
    AsyncTask* task = new AsyncTask(func, [=]() { if (postTask != nullptr) { postTask(); HideProgressBar(); }});
    QThread* thread = new QThread();
    task->moveToThread(thread);

    connect(thread, &QThread::started, this, &MainWidget::ShowProgressBar);
    connect(thread, &QThread::started, task, &AsyncTask::RunTask);
    connect(task, &AsyncTask::TaskFinished, task, &AsyncTask::RunPostTask);
    connect(thread, &QThread::finished, task, &QObject::deleteLater);
    connect(thread, &QThread::finished, thread, &QObject::deleteLater);

    thread->start();
}

欢迎提出任何建议。

【问题讨论】:

  • 什么是StartAsync?它有什么作用?您有相关参考的链接吗?
  • @Someprogrammerdude 已编辑
  • 如果我冒险猜测,它必须是fileToLoad = make_shared&lt;string&gt; 部分。这将创建一个全新的 shared_ptr&lt;string&gt; 对象,与两个 lambda 捕获的对象完全无关。也许跳过共享指针的事情,只是通过引用捕获一个普通的std::string
  • 你确定吗?我认为 lambda 会破坏本地对象,即使它在超出范围后被引用捕获,这就是为什么我使用这里建议的 shared_ptr 东西*.com/questions/30823836/…
  • StartAsync 不带 lambda,但函数,它们不一样。

标签: c++ lambda shared-ptr


【解决方案1】:

当您为 std::shared_ptr 分配新值时 - 您创建了一个新的共享值,它与前一个没有任何联系(您可以查看两个 shared_ptrs 的计数器)。你应该改变

fileToLoad = make_shared<string>(files.first().toUtf8().constData());

*fileToLoad  = files.first().toUtf8().constData()

(当然要事先检查 fileToLoad 不为空)

【讨论】:

    【解决方案2】:

    您的代码将无法工作,因为在第一个 lambda 中,您会覆盖 lambda 中的临时指针。您可以做的是覆盖指针后面的std::string,它应该可以正常工作:

    auto fileToLoad = make_shared<string>();
        StartAsync(
            [=]()
        {
    
            QDir dir(dirPath.c_str());
            QString fileExtension(fileExt.c_str());
    
            for (int i = 0; i < 150; i++)
            {
                auto files = dir.entryList(QStringList() << fileExtension << fileExtension.toUpper(), QDir::Files);
                if (!files.empty())
                {
                    //fileToLoad.reset(new string(files.first().toUtf8().constData()));
                    *fileToLoad = files.first().toStdString();
                    break;
                }
    
                this_thread::sleep_for(chrono::milliseconds(200));
            }
        },
            [=]()
        {
            if (fileToLoad == nullptr)
            {
                DisplayMessage("Timeout reached");
            }
            else
            {
                doFunc(*fileToLoad);
            }
        });
    

    【讨论】:

    • 如果同时访问两个 lambda 会发生什么?
    • 它是 UB,但 StartAsync 代码证明它们从来不是 ;)