7 Ekim 2020 Çarşamba

Closure - Capture By Reference

1. İsim Vermeden Capture
Closure 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;
    foo(int &x) : x(x) {}
    void operator()() const { x += 1; }
İsim vermeden capture ve isim vererek capture arasındaki fark şöyle
int main()
  int num = 50;
  [&] { std::cout << num << '\n'; }(); // num captured by reference
  [=] { std::cout << num << '\n'; }(); // num captured by value

  [&num] { std::cout << num << '\n'; }(); // by reference
  [num] { std::cout << num << '\n'; }();  // by value
Ö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()
  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 [&]
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))

Açıklaması şöyle
This ends up grabbing rect and point by reference and also gives you access to this...
2. İsim İle Capture
Şöyle yaparız. Sadece cap değişkenine erişileceği belirtilir.
int main() { 
  const int ci = 0;
  auto &cap = ci;
  auto lambda = [&cap]() { };
İsim ile capture ve isim olmadan capture arasındaki fark şöyle.
vector<int> vec;

auto foo = [&vec](){
  //do something

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 Capture
Saç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(a); // uncommenting this should fail the build
    std::cout << a.a << " " << b.a << "\n";
    // expected output 25 0

6 Ekim 2020 Salı


C++20 ile geliyor. std::type_identity aslında bir struct. Bu struct ile type bilgisi kod içinde rahatça dolaştırılabilir.

Şöyle yaparız. int ile çağrılan birinci kod type alan type_of metodunu tetikler. int{} yani değişken ile çağrılan ikinci kod, değişken alan birinci type_of() metodunu tetikler.
template<auto VAR> //Değişken
constexpr auto type_of() {
    return std::type_identity<decltype(VAR)>{};

template<typename T> //Type
constexpr auto type_of() {
    return std::type_identity<T>{};

template<typename T, typename... Args>
auto create(std::type_identity<T>, Args&&... args) {
  return T{std::forward<Args>(args)...};

auto i1 = create(type_of<int>(), 7); //Type
auto i2 = create(type_of<int{}>(), 7); //Değişken

Alexander Stepanov

STL'in yaratıcısının amacı şöyleydi.
Alexander Stepanov worked out you could decouple container operations from the operated on data, and algorithms from the containers they operate on. All while generating code that was close to the performance of hand-crafted C.
Eğer STL veri yapılarına arayüz eklenirse sonucu şu olur.
When you add a virtual interface to an object, there is a bunch of overhead that is added.

First, a per-implementation-class virtual function table has to exist at runtime. Second, RTTI is added. Third, inlining opportunities evaporate. Forth, the implementation objects have to carry around an extra vtable pointer. Fifth, dispatch to methods requires extra layers of indirection. Sixth, knock-on types like iterators get increasingly complex.
Bu Yüzden STL Veriyapıları Interface Kullanmazlar
Açıklaması şöyle
Other languages have chosen a different path. Languages like Java and C# have almost all objects heap-allocated with inheritance and virtual tables. Objects are actually garbage collected references to objects, and memory locality is near impossible.

The cost of this is roughly a 2x to 3x performance reduction in most tasks. They can get around this in narrow cases by either using external libraries, or by very carefully writing code that their optimizer can remove all of the object overhead from.

For many people that 2x to 3x reduction in performance is a-ok. After all, investment in performance is fungible, and many tasks are much easier in Java and C#. So you can write a quicker app that hobbles along in C#/Java, then focus your work on the critical path. Doubling the performance of code is pretty typical when you put brain-sweat into it.

C++ isn't really an OO language. It has functional, OO and procedural ways of writing C++.
Bazı Oyun Motroları Neden STL Kullanmıyor?
Sebebini bilmiyorum. Örneğin Unreal Engine kullanmıyor
- Bazıları STL veri yapılarının performansından şikayet ediyor. 
- Bazıları da bu motorlar geliştirilirken STL henüz mevcut değildi diyorlar.