c++:将 shared_ptr 传递给 lambda 的有效方法
c++: Efficient way to passing shared_ptr to a lambda
我几年前创建了一个小程序,最近开始使用智能指针。因此,出于实践原因,我根据 Scott Meyers - Effective Modern C++ 一书重构了部分代码。
想象一个 class,它拥有另一个 class 的成员 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_ptr,因为这会使速度变慢。另外,不关心经理是否还活着就好了。
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 leak and Capture by universal ref,但对我帮助不大。
对于这种情况,我总是建议首先弄清楚这个问题:我的 lambda 在 this
的生命周期后是否可以合法调用?如果是这样,捕获 this
将不是去这里的方法。一个类似的问题是:我的 lambda 是否允许延长 this
的生命周期?如果是这样,通过 this
的共享指针捕获 this
和相应的 shared_from_this
方法是一种常见的方案,但总是有额外副本的缺点(以及可能的 unclear/complex this
...的生命周期)。
在你完全清楚这些问题的前提下,这里假设lambda must/can在this
的生命周期后不被调用,简单捕获this
是正如 NathanOliver 所说的最简单和最便宜的解决方案,并为您提供了额外的提示,即对您的 lambda 的任何调用都需要一个合法的 this
-pointer。对于只捕获一个参数,如果没有其他成员,largest_prime 的简单原始指针捕获解决方案有时会更明确或至少更清晰(不像 this
-capture 这样的锤子)或成员方法在你的 lambda 主体中是必需的,即也许 lambda 的工作在语义上与你的实际 class 有点分离,并且可能在你的 class 不属于上下文的地方进一步使用通过设计。
我几年前创建了一个小程序,最近开始使用智能指针。因此,出于实践原因,我根据 Scott Meyers - Effective Modern C++ 一书重构了部分代码。
想象一个 class,它拥有另一个 class 的成员 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_ptr,因为这会使速度变慢。另外,不关心经理是否还活着就好了。
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 leak and Capture by universal ref,但对我帮助不大。
对于这种情况,我总是建议首先弄清楚这个问题:我的 lambda 在 this
的生命周期后是否可以合法调用?如果是这样,捕获 this
将不是去这里的方法。一个类似的问题是:我的 lambda 是否允许延长 this
的生命周期?如果是这样,通过 this
的共享指针捕获 this
和相应的 shared_from_this
方法是一种常见的方案,但总是有额外副本的缺点(以及可能的 unclear/complex this
...的生命周期)。
在你完全清楚这些问题的前提下,这里假设lambda must/can在this
的生命周期后不被调用,简单捕获this
是正如 NathanOliver 所说的最简单和最便宜的解决方案,并为您提供了额外的提示,即对您的 lambda 的任何调用都需要一个合法的 this
-pointer。对于只捕获一个参数,如果没有其他成员,largest_prime 的简单原始指针捕获解决方案有时会更明确或至少更清晰(不像 this
-capture 这样的锤子)或成员方法在你的 lambda 主体中是必需的,即也许 lambda 的工作在语义上与你的实际 class 有点分离,并且可能在你的 class 不属于上下文的地方进一步使用通过设计。