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 和演算法並不一定會使程式碼更快。 相反,最大的優點是,查找、排序、刪除的意圖在程式碼中表達得很清楚。