在几个可变 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 你的意思是[&myVector]
而不是[myVector=move(myVector)]
两个lambda?我试过了,它会导致程序崩溃。
@DonaldDuck ,您将向量移动到第一个 lambda。由于std::vector
支持移动语义,因此您必须预计向量将在第一个 lambda 之外变为空(在第一个 connect
调用之后)。
【参考方案1】:
在您当前的代码中,您从向量中移动了两次。这样做会导致第二个 lambda 获得一个处于有效但未指定状态的向量。您需要做的是在两个 lambda 之间共享向量。由于您是在要离开其作用域的函数中执行此操作,因此仅引用向量是不够的,因为向量将超出作用域并且 lambda 将具有悬空引用。
您可以做的是创建一个 std::shared_ptr<std::vector<QString>>
并在每个 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->size()]
更改为[myVector->size() - 1]
,因为vector[size()]
是您无法访问的向量的末尾。
【讨论】:
我是否需要任何#include
才能使用std::shared_ptr
?
@DonaldDuck 是的。 #include <memory>
是您需要的。如果您想坚持使用 Qt 类型,Qt 可能有自己的版本。我只是使用了std
一个,好吧,标准的:-)
如果我想在lambda中使用另一个变量而不改变它,例如如果另一个变量是int myVar
,我应该使用[myVar,=]
吗?
@DonaldDuck 如果您使用 [=],它将按您在 lambda 正文中使用的值捕获所有内容。如果您需要其他选项,请参阅 Lambda 捕获部分here以上是关于在几个可变 lambda 中更改相同的向量的主要内容,如果未能解决你的问题,请参考以下文章