簡體   English   中英

如何在 C++ Lambda 的向量中捕獲元素?

[英]How can I capture the element in a vector in C++ Lambda?

設想:

我用 Lambda 初始化了一個實例,其中 Lambda 可以通過引用捕獲實例來修改實例 state。 當我將實例放入向量中並調用 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 個實例在 memory 中有 2 個不同的地址,但我不明白:為什么會這樣?這會如何影響結果?)
  • 我可以通過捕獲原始引用的 Lambda 來修改容器實例 state,反之亦然?

根據@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++ 和 object它占據的 memory。

我可以通過捕獲原始引用的 Lambda 來修改容器實例 state,反之亦然?

因為它們是獨立的對象,所以它們需要某種相互引用的方式,例如BoolState * other成員。

將元素放置到容器中確實會在適當位置構造元素。 使用您提供的參數調用構造函數。 當您只需將其復制/移動到容器中時,它有助於避免創建不必要的實例。

但是,如果您確實已經有一個實例,那么放置一個元素與推送它並沒有太大區別:該參數用於調用復制構造函數,您最終會在容器中獲得一個副本。

術語可能有點誤導,因為您永遠不能先創建 object,然后將 object 放入容器中。 考慮一個 c 數組的簡單情況:

int x;
int a[3];

沒有辦法擁有&x == &a[0] ,即容器內的元素可以相等,但與外面的元素不同。 當然,您可以使用一定程度的間接(例如指針)來模擬它。

這是真正的最小示例:

#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

現場演示

向量擁有它們的內容。 他們通過復制你給他們的東西來做到這一點。

您在main的 object 與向量中的 object 不同。 修改一個不會修改另一個。

這並不意味着你不能做你想做的事,但你必須給向量中的 object 一個名字才能捕獲它:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM