Skip to the content.

31 捕获的潜在问题

#include <cassert>

int main() {
  int x = 1;
  auto f = [x] { return x; };
  auto g = [x]() mutable { return ++x; };
  x = 42;  // 不改变 lambda 中已经捕获的 x
  assert(f() == 1);
  assert(g() == 2);
}
#include <cassert>

int main() {
  int x = 1;
  auto f = [&x] { return x; };
  x = 42;
  assert(f() == 42);
}
#include <functional>
#include <iostream>

std::function<void()> f() {
  int x = 0;
  return [&]() { std::cout << x; };
}

int main() {
  f()();  // x 已被析构,值未定义
}
#include <iostream>

struct A {
  auto f() {
    // 如果去掉 =,或改为捕获 i 就会出错
    return [=] { std::cout << i; };
  };
  int i = 1;
};

int main() {
  A a;
  a.f()();  // 1
}
#include <iostream>

struct A {
  auto f() {
    return [this] { std::cout << i; };  // i 被视为 this->i
  };
  int i = 1;
};

int main() {
  A a;
  auto x = a.f();  // 内部的 i 与 a.i 绑定
  a.i = 2;
  x();  // 2
}
#include <iostream>
#include <memory>

struct A {
  auto f() {
    return [this] { std::cout << i; };
  };
  int i = 1;
};

auto g() {
  auto p = std::make_unique<A>();
  return p->f();
}  // p 被析构

int main() {
  g()();  // A 对象 p 已被析构,lambda 捕获的 this 失效,i 值未定义
}
#include <iostream>
#include <memory>

struct A {
  auto f() {
    return [*this] { std::cout << i; };
  };
  int i = 1;
};

// 现在 lambda 捕获的是对象的一个拷贝,不会被原对象的析构影响
auto g() {
  auto p = std::make_unique<A>();
  return p->f();
}

int main() {
  A a;
  auto x = a.f();  // 只保存此刻的 a.i
  a.i = 2;
  x();  // 1
  g()();  // A 对象 p 已被析构,lambda 捕获的 this 失效,i 值未定义
}
#include <iostream>
#include <memory>

struct A {
  auto f() {
    int j = i;
    return [j] { std::cout << j; };
  };
  int i = 1;
};

auto g() {
  auto p = std::make_unique<A>();
  return p->f();
}

int main() {
  g()();  // 1
}
#include <iostream>
#include <memory>

struct A {
  auto f() {
    return [i = i] { std::cout << i; };
  };
  int i = 1;
};

auto g = [p = std::make_unique<A>()] { return p->f(); };

int main() {
  g()();  // 1
}
#include <cassert>

static int i = 1;

int main() {
  constexpr auto f = [] { return i; };
  assert(f() == i);
}

32 用初始化捕获将对象移入闭包

auto p = std::make_unique<int>(42);
auto f = [&p]() { std::cout << *p; };
auto p = std::make_unique<int>(42);
auto f = [p = std::move(p)]() { std::cout << *p; };
assert(p == nullptr);
auto f = [p = std::make_unique<int>(42)]() { std::cout << *p; };
class A {
 public:
  A(std::unique_ptr<int>&& p) : p_(std::move(p)) {}
  void operator()() const { std::cout << *p_; }

 private:
  std::unique_ptr<int> p_;
};

auto f = A(std::make_unique<int>(42));
auto f = std::bind([](const std::unique_ptr<int>& p) { std::cout << *p; },
                   std::make_unique<int>(42));
std::vector<int> v;  // 要移动到闭包的对象
// C++14:初始化捕获
auto f = [v = std::move(v)] {};
// C++11:模拟初始化捕获
auto g = std::bind([](const std::vector<int>& v) {}, std::move(v));
auto f = [](auto x, auto y) { return x < y; };

// 上述 lambda 相当于生成如下匿名类
struct X {
  template <typename T, typename U>
  auto operator()(T x, U y) const {
    return x < y;
  }
};
std::vector<int> v;
// C++14:初始化捕获
auto f = [v = std::move(v)]() mutable {};
// C++11:模拟可变 lambda 的初始化捕获
auto g = std::bind([](std::vector<int>& v) {}, std::move(v));

33 用 decltype 获取 auto&& 参数类型以 std::forward

auto f = [](auto x) { return g(x); };
// 传入参数是 auto,类型未知,std::forward 的模板参数应该是什么?
auto f = [](auto&& x) { return g(std::forward <???> (x)); };
auto f = [](auto&& x) { return g(std::forward<decltype(x)>(x)); };
auto f = [](auto&&... args) {
  return g(std::forward<decltype(args)>(args)...);
};

34 用 lambda 替代 std::bind

int l = 0;
int r = 9;
auto f = [l, r](const auto& x) { return l <= x && x <= r; };

// 用 std::bind 实现相同效果
using namespace std::placeholders;
// C++14
auto f = std::bind(std::logical_and<>{}, std::bind(std::less_equal<>{}, l, _1),
                   std::bind(std::less_equal<>(), _1, r));
// C++11
auto f = std::bind(std::logical_and<bool>{},
                   std::bind(std::less_equal<int>{}, l, _1),
                   std::bind(std::less_equal<int>{}, _1, r));
void f(const A&);

using namespace std::placeholders;
A a;
auto g = std::bind(f, std::ref(a), _1);
void f(int) {}
void f(double) {}

auto g = [] { f(1); };                                 // OK
auto g = std::bind(f, 1);                              // 错误
auto g = std::bind(static_cast<void (*)(int)>(f), 1);  // OK
#include <chrono>
#include <functional>
#include <iostream>
#include <thread>

void f(std::chrono::steady_clock::time_point t, int i) {
  std::this_thread::sleep_until(t);
  std::cout << i;
}

int main() {
  using namespace std::chrono_literals;
  using namespace std::placeholders;

  auto g1 = [](int i) { f(std::chrono::steady_clock::now() + 3s, i); };
  g1(1);  // 3 秒后打印 1

  auto g2 = std::bind(f, std::chrono::steady_clock::now() + 3s, _1);
  g2(1);  // 调用 std::bind 后的 3 秒打印 1,而非调用 f 后的 3 秒
}
auto g = std::bind(f,
                   std::bind(std::plus<>{}, std::chrono::steady_clock::now(),
                             std::chrono::seconds{3}),
                   std::placeholders::_1);
struct X {
  template <typename T>
  void operator()(const T&) const;
};

X x;
auto f = std::bind(x, _1);  // f 可以接受任意参数类型
X a;
auto f = [a](const auto& x) { a(x); };

std::bind 用法示例

#include <functional>
#include <iostream>

void f(int a, int b, int c) { std::cout << a << b << c; }

int main() {
  using namespace std::placeholders;
  auto x = std::bind(f, _2, _1, 3);
  // _n 表示 f 的第 n 个参数
  // x(a, b, c) 相当于 f(b, a, 3);
  x(4, 5, 6);  // 543
}
#include <cassert>
#include <functional>

void f(int& n) { ++n; }

int main() {
  int n = 1;
  auto x = std::bind(f, n);
  x();
  assert(n == 1);
  auto y = std::bind(f, std::ref(n));
  y();
  assert(n == 2);
}
#include <cassert>
#include <functional>
#include <iostream>

void f(int a, int b) { std::cout << a << b; }
int g(int n) { return n + 1; }

int main() {
  using namespace std::placeholders;
  auto x = std::bind(f, _1, std::bind(g, _1));
  x(1);  // 12
}
#include <cassert>
#include <functional>

struct A {
  int f(int n) const { return n; }
};

int main() {
  A a;
  auto x = std::bind(&A::f, &a, std::placeholders::_1);
  assert(x(42) == 42);
  auto y = std::bind(&A::f, a, std::placeholders::_1);
  assert(y(42) == 42);
}
#include <cassert>
#include <functional>
#include <memory>

struct A {
  int i = 0;
};

int main() {
  auto x = std::bind(&A::i, std::placeholders::_1);
  A a;
  assert(x(a) == 1);
  assert(x(&a) == 1);
  assert(x(std::make_unique<A>(a)) == 1);
  assert(x(std::make_shared<A>(a)) == 1);
}
#include <functional>
#include <iostream>
#include <random>

int main() {
  std::default_random_engine e;
  std::uniform_int_distribution<> d(0, 9);
  auto x = std::bind(d, e);
  for (int i = 0; i < 20; ++i) {
    std::cout << x();
  }
}

std::function 用法示例

#include <cassert>
#include <functional>

struct X {
  int operator()(int n) const { return n; }
};

int main() {
  std::function<int(int)> f = X();
  assert(f(0) == 0);
}
#include <cassert>
#include <functional>

int f(int i) { return i; }

int main() {
  std::function<int(int)> g = std::bind(f, std::placeholders::_1);
  assert(g(0) == 0);
}
#include <cassert>
#include <functional>

struct A {
  int f(int n) const { return n; }
};

int main() {
  A a;
  std::function<int(int)> g = std::bind(&A::f, &a, std::placeholders::_1);
  assert(g(0) == 0);
}
#include <cassert>
#include <functional>

struct A {
  int f(int n) const { return n; }
};

int main() {
  std::function<int(A&, int)> g1 = &A::f;
  A a;
  assert(g1(a, 0) == 0);

  std::function<int(const A&, int)> g2 = &A::f;
  const A b;
  assert(g2(b, 0) == 0);
}
#include <cassert>
#include <functional>

struct A {
  int i = 0;
};

int main() {
  std::function<int(const A&)> g = &A::i;
  A a;
  assert(g(a) == 0);
}