【问题标题】:c++: Efficient way to passing shared_ptr to a lambdac ++:将shared_ptr传递给lambda的有效方法
【发布时间】:2021-06-23 08:24:22
【问题描述】:

几年前我创建了一个小程序,最近我开始关注使用智能指针。因此,出于实践原因,我根据 Scott Meyers - Effective Modern C++ book 重构了部分代码。

想象一个类,它拥有另一个类的成员 shared_ptr,它管理一些其他不必要对象的生命周期。

class Foo {
...
    std::shared_ptr<Bar> manager;

    void DoSomeWork();
}

DoSomeWork 方法的实现包含一个 lambda collectIfNeighbor,因为它在某些部分经常使用,这是实现正确行为的最简单方法。主要思想是只捕获 lambda 中需要的内容,并使用智能指针而不是到处检查 nullptr。

void Foo::DoSomeWork(){
    std::vector<Object*> neighbors;
    auto collectIfNeighbor = [this, &neighbors](const Position& pos) {
        ...    
        if ( *some condition* )
            neighbors.push_back(manager->GetObject(pos));
    };
    collectIfNeighbor(Position(1,1));    // example usage
    ...
}

所以这里的问题是我在 lambda 内部捕获了this,但我并不需要全部,只需要经理。将 shared_ptr 传递给 lambda 的最有效方法是什么?

如果可能,我不想传递整个this,因为我只使用一个成员。要么我不想创建和销毁大量的 shared_ptrs,因为它会使它变慢。另外,不用关心经理是否还活着也不错。

还有其他实现 lambda 的方法。将 shared_ptr 复制到本地,并通过引用传递它。但是我在本地制作和额外的副本,我担心每次 lambda 调用时。另一种方法是简单地创建一个常规指针并将其传递给 lambda。

std::shared_ptr<Bar> localManager = manager;
auto lambdaV1= [&localManager, &neighbors](const Position& pos) {
    ...    
    if ( *some condition* )
        neighbors.push_back(manager->GetObject(pos));
};
Bar* localManagerPtr = manager.get();
auto lambdaV2= [&localManagerPtr , &neighbors](const Position& pos) {
    ...    
    if ( *some condition* && manager != nullptr)    // extra check on manager
        neighbors.push_back(manager->GetObject(pos));
};

我检查了Passing shared_ptr to lambda cause memory leakCapture by universal ref,但对我没有多大帮助。

【问题讨论】:

  • 不参与所有权时,传递原始指针
  • "我不想传递整个 this" 听起来您担心捕获 this 会复制对象。但是捕获this 只捕获一个指针。
  • 除非您打算更改 localManagerPtr 指向的对象,否则您应该只按值捕获指针。
  • 捕获this 可能是最简单和最便宜的解决方案。除非您担心 this 的生命周期会超过 lambda,否则您应该坚持下去。
  • C++14 允许“(重新)命名”捕获,如果你想更明确的话。

标签: c++ c++11 lambda shared-ptr


【解决方案1】:

对于这种情况,我总是建议先弄清楚这个问题:我的 lambda 在this 的生命周期之后可以合法地调用吗?如果是这样,捕获this 将不是这里的方法。一个类似的问题是:我的 lambda 是否允许延长 this 的生命周期?如果是这样,通过this 的共享指针捕获this 和相应的shared_from_this 方法是一种常见方案,但总是存在额外副本的缺点(以及this 可能不明确/复杂的生命周期。 .).

在您完全清楚这些问题的前提下,并假设在 this 的生命周期之后必须/不能调用 lambda,简单地捕获 this 是最简单和最便宜的解决方案,正如 NathanOliver 所说为您提供额外的提示,任何对您的 lambda 的调用都需要一个合法的this-pointer。对于只捕获一个参数,如果内部不需要其他成员或成员方法,maximum_prime 的简单原始指针捕获解决方案有时会更明确或至少更清晰一些(不像this-capture 这样的锤子) lambda 的主体,即 lambda 的工作可能在语义上与您的实际类有点分离,并且可能会在您的类不属于设计上下文的其他地方进一步使用。

【讨论】:

    猜你喜欢
    • 2015-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-12
    • 1970-01-01
    相关资源
    最近更新 更多