在几个可变 lambda 中更改相同的向量

Posted

技术标签:

【中文标题】在几个可变 lambda 中更改相同的向量【英文标题】:Change the same vector in several mutable lambdas 【发布时间】:2016-09-30 19:26:13 【问题描述】:

我有两个不同的 Qt 按钮,类型为 QPushButton* 和一个 vector<QString>。每个按钮都必须显示一个消息框,说明向量的最后一个元素的值是什么,如果用户按下是,则将特定值插入向量中。下面的代码显示了我是如何做到这一点的(QMessageBox::information 仅用于调试原因)。这是我的代码的相关部分:

std::vector<QString> myVector;
myVector.push_back("First value");
QObject::connect(button1,&QPushButton::clicked,myWidget,[myVector=move(myVector)]() mutable
    QMessageBox::information(NULL,"",std::to_string(myVector.size()).c_str());
    if(QMessageBox::question(NULL,"","The value of the last element in the vector is " + myVector[myVector.size() - 1] + ".\nDo you want to insert a new value?",QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
        myVector.push_back("Value inserted by button 1");
    
);
QObject::connect(button2,&QPushButton::clicked,myWidget,[myVector=move(myVector)]() mutable
    QMessageBox::information(NULL,"",std::to_string(myVector.size()).c_str());
    if(QMessageBox::question(NULL,"","The value of the last element in the vector is " + myVector[myVector.size() - 1] + ".\nDo you want to insert a new value?",QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
        myVector.push_back("Value inserted by button 2");
    
);

我确定向量在任何时候都是空的。

当我按下按钮 1 时,一切正常。但是当我按下按钮 2 时,消息框显示矢量的大小为 0,我确定这不是真的。当我交换两个 QObject::connect 函数时,即把一个用于 Button 2 的函数放在一个用于 Button 1 的函数之前,按钮的行为会交换:Button 2 正常工作,而 Button 1 认为向量为空。

这似乎不是让两个 lambda 捕获相同向量作为可变的正确方法。这是为什么?这样做的正确方法是什么?

【问题讨论】:

您已经从同一个变量中移动了两次。想想那有什么作用。 @NathanOliver 好的,但是正确的做法是什么?仅在其中一个 lambda 中使用 move 而在另一个中不使用就足够了吗? 如果它们应该共享,为什么不在每个 lambda 中存储对向量的引用? @NathanOliver 你的意思是[&amp;myVector] 而不是[myVector=move(myVector)] 两个lambda?我试过了,它会导致程序崩溃。 @DonaldDuck ,您将向量移动到第一个 lambda。由于std::vector 支持移动语义,因此您必须预计向量将在第一个 lambda 之外变为空(在第一个 connect 调用之后)。 【参考方案1】:

在您当前的代码中,您从向量中移动了两次。这样做会导致第二个 lambda 获得一个处于有效但未指定状态的向量。您需要做的是在两个 lambda 之间共享向量。由于您是在要离开其作用域的函数中执行此操作,因此仅引用向量是不够的,因为向量将超出作用域并且 lambda 将具有悬空引用。

您可以做的是创建一个 std::shared_ptr&lt;std::vector&lt;QString&gt;&gt; 并在每个 lambda 中按值捕获该 shared_ptr。这可以确保向量具有适当的生命周期,并且两个按钮都在同一个向量上运行。你的可能看起来像

std::shared_ptr<std::vector<QString>> myVector;
myVector->push_back("First value");
QObject::connect(button1,&QPushButton::clicked,myWidget,[=]() mutable
    QMessageBox::information(NULL,"",std::to_string(myVector->size()).c_str());
    if(QMessageBox::question(NULL,"","The value of the last element in the vector is " + (*myVector)[myVector.size() - 1] + ".\nDo you want to insert a new value?",QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
        myVector->push_back("Value inserted by button 1");
    
);
QObject::connect(button2,&QPushButton::clicked,myWidget,[=]() mutable
    QMessageBox::information(NULL,"",std::to_string(myVector.size()).c_str());
    if(QMessageBox::question(NULL,"","The value of the last element in the vector is " + (*myVector)[myVector->size() - 1] + ".\nDo you want to insert a new value?",QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
        myVector->push_back("Value inserted by button 2");
    
);

另请注意,我将[myVector-&gt;size()] 更改为[myVector-&gt;size() - 1],因为vector[size()] 是您无法访问的向量的末尾。

【讨论】:

我是否需要任何#include 才能使用std::shared_ptr @DonaldDuck 是的。 #include &lt;memory&gt; 是您需要的。如果您想坚持使用 Qt 类型,Qt 可能有自己的版本。我只是使用了std 一个,好吧,标准的:-) 如果我想在lambda中使用另一个变量而不改变它,例如如果另一个变量是int myVar,我应该使用[myVar,=]吗? @DonaldDuck 如果您使用 [=],它将按您在 lambda 正文中使用的值捕获所有内容。如果您需要其他选项,请参阅 Lambda 捕获部分here

以上是关于在几个可变 lambda 中更改相同的向量的主要内容,如果未能解决你的问题,请参考以下文章

在几个JLabel中设置相同的gif作为图标

在几个向量中减少向量时间的百分比

在c ++中给出两个整数向量(相同的大小和类型),我想从最小到最大的元素对一个进行排序并更改第二个向量的顺序[重复]

如何创建可变参数泛型 lambda?

在 Android 应用程序之间共享不可变文件

如何划分可变借入的向量?