从 C++ 基础到掌握 — 第 11 集
使用 Lambda 和标准算法
该博客上撰写的文章是出于教学目的而创建的。 另外,文章中的信息可能不正确,请谨慎。
用于查找或排序容器中的特定怪物以及移除死亡怪物的代码经常出现。 您可以使用 for 语句创建自己的算法,但使用标准算法可以使代码的目的更加明显。
拉姆达
lambda 是直接编写的没有名称的函数。
int monsterId = 10;
auto isTarget = [monsterId](const std::shared_ptr<Monster>& monster)
{
return monster->GetId() == monsterId;
};
[]是捕获列表。 [monsterId]通过复制来捕获值,[&]通过引用捕获外部变量。[this]使用当前对象。
引用捕获很方便,但如果 lambda 的生存时间比原始变量长,则可能会很危险。 如果您清楚地仅捕获必要的值,则代码会更容易阅读。
find_if
auto iter = std::find_if(
activeMonsters.begin(),
activeMonsters.end(),
[monsterId](const auto& monster)
{
return monster->GetId() == monsterId;
}
);
if (iter != activeMonsters.end())
{
currentTarget = *iter;
}
find_if 返回满足条件的第一个元素的迭代器。 如果未找到,则返回传递范围的末尾。
sort
首先对生命值最低的怪物进行排序,如果生命值相同,则可以将 ID 较低的怪物放在前面。
std::sort(
activeMonsters.begin(),
activeMonsters.end(),
[](const auto& a, const auto& b)
{
if (a->GetHealth() != b->GetHealth())
{
return a->GetHealth() < b->GetHealth();
}
return a->GetId() < b->GetId();
}
);
如果比较函数返回 true,则意味着 a 必须位于 b 之前。 如果比较标准相互矛盾,则排序结果不可信,因此必须遵守严格的缩写顺序。
remove_if 和擦除
auto newEnd = std::remove_if(
activeMonsters.begin(),
activeMonsters.end(),
[](const auto& monster)
{
return monster->IsDead();
}
);
activeMonsters.erase(newEnd, activeMonsters.end());
remove_if 不会直接减小容器大小。 将剩余元素向前移动并返回新的逻辑结尾。实际的擦除是通过擦除来执行的。
当从向量中删除元素时,后续的迭代器和引用可能会变得无效。 当一个shared_ptr元素被删除时,它的引用计数就会减少,如果它是最后一个所有者,那么该对象也会被销毁。
使用 lambda 和算法并不一定会使代码更快。 相反,最大的优点是,查找、排序、删除的意图在代码中表达得很清楚。