1. İsim Vermeden CaptureClosure içinde kullanılan değişkenler referans şeklinde saklanır. Değişkenin ömrünün closure'dan fazla olmasına dikkat etmek gerekir. Açıklaması
şöyle
a comma-separated list of zero or more captures, optionally beginning with a capture-default. Capture list can be passed as follows [...]:
[a,&b] where a is captured by value and b is captured by reference.
[this] captures the this pointer by value
[&] captures all automatic variables odr-used in the body of the lambda by reference
[=] captures all automatic variables odr-used in the body of the lambda by value
[] captures nothing
Üretilen Kod
Elimize şöyle bir closure
olsun.
[&] { x += 1; } // capture by reference
Derleyici şöyle bir kod üretir.
class foo {
int &x;
public:
foo(int &x) : x(x) {}
void operator()() const { x += 1; }
};
Kullanım
İsim vermeden capture ve isim vererek capture arasındaki fark
şöyleint main()
{
int num = 50;
[&] { std::cout << num << '\n'; }();
[=] { std::cout << num << '\n'; }();
[&num] { std::cout << num << '\n'; }();
[num] { std::cout << num << '\n'; }();
}
Örnek - dangling reference
Elimizde şöyle bir kod
olsun#include <iostream>
#include <functional>
std::function<void ()> f()
{
int x = 666;
return [&] { std::cout << x << std::endl; };
}
int main()
{
f()();
return 0;
}
Bu kod hatalı. Açıklaması
şöyle.
You capture x by reference in the lambda and after leaving f() it becomes a dangling reference as x gets destroyed. You have a classic UB. To avoid it you can capture x by value by writing [x] or [=] instead of [&]
Örnek
Elimizde şöyle bir kod
olsun. Burada [&] ile hem yerel değişkenler hem de
this kullanılabiliyor.
Rect rect;
Point point;
auto someLambda = [&](const SomeType& var)
{
if (rect.Contains(point))
{
var.Something();
}
this->MemberFunction();
};
This ends up grabbing rect and point by reference and also gives you access to this...
2. İsim İle Capture
Örnek
Şöyle
yaparız. Sadece
cap değişkenine erişileceği belirtilir.
int main() {
const int ci = 0;
auto &cap = ci;
auto lambda = [&cap]() { };
}
Örnekİsim ile capture ve isim olmadan capture arasındaki fark
şöyle.
vector<int> vec;
//a
auto foo = [&vec](){
//do something
};
//b
auto foo = [&v = vec](){
//do something
};
2.1 İsim İle Capture ve const Değişken
Yakalama işleminde değişkenin const olup olmadığı önemlidir. const bir değişken
değiştirilemez.
const int i = 5;
auto b = [&i]() { i++; }; //error on i++
2.2 İsim İle Capture ve const ClosureŞöyle
yapılır. Lambda kendi içindeki state bilgisini değiştiremez.
int foo(int i)
{
const auto a = [&i](){...};
...
}
2.2 İsim İle Capture ve Değişkene Farklı İsim Vermek
Örnekte ci değişkenine lamda içinde cap değişkeni olarak
erişilir. Yani sadece değişkene farklı bir isim tanımlanır.
int main() {
const int ci = 0;
auto lambda = [ &cap = ci ]() { };
}
Cast ile CaptureSaçma gelse bile capture ederken cast işlemi yapılabiliyor. Const olmayan bir değişken const
yapılabiliyor.
#include <iostream>
#include <type_traits>
struct noncopyable
{
int a;
const noncopyable& operator=(noncopyable&&) = delete;
noncopyable(noncopyable&&) = delete;
const noncopyable& operator=(const noncopyable&) = delete;
noncopyable(const noncopyable&) = delete;
~noncopyable() = default;
};
void modify(noncopyable& a)
{
a.a = 0;
}
int main()
{
noncopyable a = { 25 }, b = { 42 };
[&, &a = static_cast<const noncopyable&>(a)]{
modify(b);
//modify(a); // uncommenting this should fail the build
}();
std::cout << a.a << " " << b.a << "\n";
// expected output 25 0
}