據我所知,lambda 捕獲變數生命周期系結到 lamda 物件的生命周期。例如,在這種情況下:
#include <string>
#include <vector>
using namespace std;
class SomeCla {
public:
constexpr SomeCla(int i, float f) noexcept : _i(i), _f(f) {}
~SomeCla() {
puts("dtor");
}
SomeCla(const SomeCla&) = default;
SomeCla(SomeCla&&) = default;
SomeCla& operator=(const SomeCla&) = default;
SomeCla& operator=(SomeCla&&) = default;
constexpr float total() const noexcept { return static_cast<float>(_i) _f; }
private:
int _i;
float _f;
};
int main() {
vector<float> vec = { 1.0f };
const auto filler = [someCla = SomeCla(1, 2.0f)](vector<float>& someVec, int val) {
someVec.push_back(someCla.total() static_cast<float>(val));
};
for (int i = 0; i < 10; i) {
filler(vec, i * 3);
}
return static_cast<int>(vec.size());
}
輸出是:
dtor
即使我們多次呼叫 lamda,“dtor”也只放置了一次,這是意料之中的。
但是關于 std::algorithm 函式有一些奇怪的事情。如果我們使用它們:
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class SomeCla {
public:
constexpr SomeCla(int i, float f) noexcept : _i(i), _f(f) {}
~SomeCla() {
puts("dtor");
}
SomeCla(const SomeCla&) = default;
SomeCla(SomeCla&&) = default;
SomeCla& operator=(const SomeCla&) = default;
SomeCla& operator=(SomeCla&&) = default;
constexpr float total() const noexcept { return static_cast<float>(_i) _f; }
private:
int _i;
float _f;
};
int main() {
vector<float> vec = { 1.0f };
erase_if(vec, [someCla = SomeCla(1, 2.0f)](float ele) {
return ele == someCla.total();
});
puts("continue");
{
const auto filler = [someCla = SomeCla(1, 2.0f)](vector<float>& someVec, int val) {
someVec.push_back(someCla.total() static_cast<float>(val));
};
for (int i = 0; i < 10; i) {
filler(vec, i * 3);
}
}
puts("continue2");
ignore = none_of(vec.cbegin(), vec.cend(), [someCla = SomeCla(1, 2.0f)](float ele) { return ele == -1.0f; });
puts("heyyyyyyyyyyyyy");
ignore = any_of(vec.cbegin(), vec.cend(), [someCla = SomeCla(1, 2.0f)](float ele) { return ele == 1.0f; });
return static_cast<int>(vec.size());
}
輸出將如下所示:
dtor
dtor
dtor
dtor
dtor
dtor
dtor
continue
dtor
continue2
dtor
dtor
dtor
dtor
dtor
dtor
heyyyyyyyyyyyyy
dtor
dtor
dtor
dtor
dtor
dtor
dtor
std::erase_if 上有 7 個“dtor”,std::none_of 上有 6 個“dtor”,std::any_of 上有 7 個“dtor”,正常呼叫 lambda 時只有 1 個“dtor”(如預期的那樣)。這些數字與容器大小無關。我試過并得到相同的數字。
所以,問題是,它是一個錯誤還是依賴于 std::algorithm 函式的實作細節?看來,這些 std::algorithm 函式可能會多次構造和破壞 lamda 物件,這就是為什么我們的 lambda 捕獲變數被多次構造和破壞的原因。
順便說一句,另一個奇怪的事情是 MSVC 構建上的這些數字(即 2)低于 GCC 和 Clang,但仍然大于 1。這是 MSVC 輸出:
dtor
dtor
continue
dtor
continue2
dtor
dtor
heyyyyyyyyyyyyy
dtor
dtor
在這里可以測驗:https ://godbolt.org/z/nWd77c9o6
現在,我決定在呼叫 std::algorithm 函式時不創建 lambda 捕獲變數(如果它們不是基本型別),我將創建變數并在 lambda 捕獲上通過參考傳遞。
uj5u.com熱心網友回復:
我無法重現確切的輸出,但我可以重現 lambda 捕獲中的物件被復制和銷毀多次。這是由于標準演算法的設計以及它留給庫實作者的自由。
特別是,傳遞給標準演算法的可呼叫物件是按值傳遞的,因此它們被期望復制起來很便宜(否則,它們可以被包裝在某種參考包裝器中)。并且當將這樣的物件(如您的情況中的 lambda)傳遞給演算法時,您必須期望它被傳遞給其他演算法。由于許多標準演算法都是可重用的構建塊,因此一種演算法通常根據一種或多種其他演算法來實作。當可呼叫物件傳遞給這些其他演算法時,它會被復制 - 因此是您的輸出。
為了完整起見,這是我可以觀察到的輸出:
dtor
dtor
dtor
dtor
dtor
dtor
dtor
continue
uj5u.com熱心網友回復:
只需在 lambda 的閉包中通過參考捕獲一個實體SomeCla,即:
SomeCla someCla(1,2.0f);
erase_if(vec, [&someCla](float ele) {
return ele == someCla.total();
});
到處改變這個給了我:
continue
continue2
heyyyyyyyyyyyyy
dtor
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/436170.html
下一篇:通過bash替換組態檔中的值
