Quantcast
Channel: vinxru
Viewing all articles
Browse latest Browse all 319

Еще один гвоздь в замыкания C++

$
0
0
В обсуждении ранее я сказал, что настоящие лямбды/замыкания не могут использовать стековые переменные, так как стек разрушается. И пример привел, который бы в javascript работал, а в C++ нет.

Но частично эта проблем решена. Когда вы создаете лямбду в функции и возвращаете её наружу, то

function<string()> test2(string x) {
  return [x] { return x; };
}

void main() {
  auto fn = test2("Hello world");
}


То реально создается две лямбды, одна в функции main. А вторая в функции test2. И при выходе из test2, одна лямбда просто копируется в другую (указатель на код и входные параметры просто копируются во внешнюю переменную). Как бы это было с числом, строкой и любым другим объектом, который можно копировать.

Вот еще пример, в котором видно, что объекты находятся в стеке. И каждое присвоение переменной вызывает копирование объекта.

Единственное, чего я не понял, это почему все объекты внутри лямбда функции константные. (в камментах уже объяснили, я забыл про слово mutable).


class Check {
public:
  int c;
  Check() { messageBox(hex(int(this))+" constructor", "", 0); c=0; }
  Check(const Check& src) { messageBox(hex(int(this))+" copy", "", 0); c=0; }
  int get() { return c++; }
};

std::function<std::string()> test2(std::string x) {
  return [x] { return x; };
}

void test() {
  Check c; // 1EBEC78 constructor
  auto fn1 = [c] { return const_cast<Check*>(&c)->get(); }; // 1EBEC74 copy
  auto fn1 = [c] mutable { return c.get(); }; // 1EBEC74 copy
  auto fn2 = fn1; // 1EBEC70 copy
  int res1 = fn1(); // 0
  int res2 = fn1(); // 1
  int res3 = fn2(); // 0
}


(Не всегда в стеке. Если данные не помещаются в std::function, размер которого всего 24 байта, то объект создается в куче, но сути дела это не меняет.)

Обойти постоянное копирование можно завернув аргументы в std::make_shared.

auto data = std::make_shared<int>(0);
auto fn = [data]() { return (*data)++; };


А если std::make_shared завернуть не аргументы лямбда-функции, а все переменные функции, в которой эта лямбда создавалась, то получим полноценное замыкание в стиле JavaScript.

Viewing all articles
Browse latest Browse all 319

Trending Articles