【问题标题】:How can I capture the element in a vector in C++ Lambda?如何在 C++ Lambda 中捕获向量中的元素?
【发布时间】:2020-07-22 08:11:35
【问题描述】:

场景:

我用其中的 Lambda 初始化了一个实例,Lambda 可以通过引用捕获实例来修改实例状态。 当我将实例放入向量中并调用 Lambda 时,Lambda 会修改原始初始化实例,而不是向量中的实例。

最小的 C++ 程序来说明:

#include <iostream>
#include <functional>
#include <vector>

struct BoolState {
    bool _stateChangeByInstanceReference = false;
    bool _stateChangeByContainerReference = false;
    std::function<void()> _changeStateByInstanceReference;
    std::function<void()> _changeStateByContainerReference;
};

int main()
{
    using namespace std;
    vector<BoolState> bss;
    BoolState bs;
    bs._changeStateByInstanceReference = [&bs]() -> void { bs._stateChangeByInstanceReference = true; };
    bs._changeStateByContainerReference = [&bss]() -> void { bss.at(0)._stateChangeByContainerReference = true; };
    bss.emplace_back(bs);
    bss.back()._changeStateByInstanceReference();
    bss.back()._changeStateByContainerReference();
    cout << "The original instance by instance reference: " << bs._stateChangeByInstanceReference << endl;
    cout << "The original instance by container reference? " << bs._stateChangeByContainerReference << endl;
    cout << "The container instance by instance reference? " << bss.back()._stateChangeByInstanceReference << endl;
    cout << "The container instance by container reference: " << bss.back()._stateChangeByContainerReference << endl;
    /*
        The original instance by instance reference: 1
        The original instance by container reference? 0
        The container instance by instance reference? 0
        The container instance by container reference: 1
    */
}

问题:

  • 由于我在 Lambda 中通过引用捕获了实例,如何 原始初始化实例和向量中的实例为 2 不同的实例? (我可以打印出 2 个实例在内存中有 2 个不同的地址,但我不明白:为什么会这样?这会如何影响结果?)
  • 能否通过 Lambda 捕获原始引用来修改容器实例状态,反之亦然?

根据@Asteroids With Wings、@idclev 463035818 和@Caleth 的解决方案:

非常感谢大家!这有助于我了解这里发生了什么以及如何解决它。

根据@Asteroids With Wings 的 push_back() 版本:

int main()
{
    using namespace std;
    vector<BoolState> bss;
    BoolState bs;
    bs._changeStateByContainerReference = [&bss]() -> void { bss.at(0)._stateChangeByContainerReference = true; };
    // Only copy container version Lambda
    bss.push_back(bs);
    // Modify in place with instance version Lambda
    BoolState& bsInbss = bss.at(0);
    bss.at(0)._changeStateByInstanceReference = [&bsInbss]() -> void { bsInbss._stateChangeByInstanceReference = true; };
    bss.at(0)._changeStateByInstanceReference();
    bss.at(0)._changeStateByContainerReference();
    cout << "The container instance by instance reference:(solved) " << bss.back()._stateChangeByInstanceReference << endl;
    cout << "The container instance by container reference: " << bss.back()._stateChangeByContainerReference << endl;
}

根据@idclev 463035818 的“真实”emplace_back() 版本

int main() {
    using namespace std;
    vector<BoolState> bss;
    bss.emplace_back(BoolState());
    BoolState& bsInbss = bss.at(0);
    bss.at(0)._changeStateByInstanceReference = [&bsInbss]() -> void { bsInbss._stateChangeByInstanceReference = true; };
    bss.at(0)._changeStateByContainerReference = [&bss]() -> void { bss.at(0)._stateChangeByContainerReference = true; };
    bss.at(0)._changeStateByInstanceReference();
    bss.at(0)._changeStateByContainerReference();
    cout << "The container instance by instance reference:(solved) " << bss.back()._stateChangeByInstanceReference << endl;
    cout << "The container instance by container reference: " << bss.back()._stateChangeByContainerReference << endl;
}

根据@Caleth,我没有再尝试修改原始实例,如果您仍然有兴趣互相引用方法,请自行尝试。

【问题讨论】:

  • 请不要在您的答案中添加解决方案。从某种意义上说,这是在破坏您的问题。但是,如果您想添加答案,可以这样做

标签: c++ lambda capture


【解决方案1】:

当我将实例放入向量中时

你不能那样做。您可以将实例复制到矢量元素中。在 C++ 中,对象它占用的内存。

是否可以通过 Lambda 捕获原始引用来修改容器实例状态,反之亦然?

因为它们是独立的对象,所以它们需要某种方式来相互引用,例如 BoolState * other 成员。

【讨论】:

  • 我已经根据您的解释更新了解决方案。感谢您的帮助!
【解决方案2】:

将元素放置到容器中确实会在适当位置构造元素。使用您提供的参数调用构造函数。当您只需将其复制/移动到容器中时,它有助于避免创建不必要的实例。

但是,如果您已经有一个实例,那么放置一个元素与推送它并没有太大区别:该参数用于调用复制构造函数,您最终会在容器中获得一个副本。

术语可能有点误导,因为您永远不能先创建一个对象,然后将该对象放入容器中。考虑 c 数组的简单情况:

int x;
int a[3];

没有办法拥有&amp;x == &amp;a[0],即容器内的元素可以相等,但不能与外面的元素相同。当然你可以用一定程度的间接(例如指针)来模拟它。

【讨论】:

  • 我已根据您的解释更新了解决方案。感谢您的帮助!
【解决方案3】:

这是 真实 最小示例?:

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v;
    
    int x = 42;
    v.emplace_back(x);
    
    std::cout << &x << '\n';
    std::cout << &v[0] << '\n';
}

// 0x7ffd008d9d14
// 0x1f7fc20

(live demo)

向量拥有它们的内容。他们通过复制你给他们的东西来做到这一点。

main 中的对象与向量中的对象不同。修改一个不会修改另一个。

这并不意味着你不能做你想做的事,但你必须给向量中的对象一个名字才能捕获它:

BoolState& bsInVector = bss.at(0);
auto func = [&bsInVector]() { /* ... */ };

【讨论】:

  • 我已根据您的代码更新了解决方案。感谢您的指导!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
  • 2010-09-20
  • 2023-03-31
  • 2020-12-04
  • 1970-01-01
相关资源
最近更新 更多