使用c ++ 17进行弱绑定

时间:2018-04-29 18:17:58

标签: c++ c++14 c++17 weak-references

我正在处理一个处理框架,其中回调被注册到事件并确保没有对已被删除的对象调用回调,我想使用弱捕获而不是通过引用捕获。使用C++14shared_from_this()进行此项工作没有问题,但使用C++17weak_from_this()如何正确实现这一点。

以下示例在使用C++17时不打印任何内容。我正在使用g ++ 6.3.0-18

#define CXX17  // When this is defined, nothing is printed
#ifdef CXX17
# include <experimental/memory>
# include <experimental/functional>
  template <typename T>
  using enable_shared_from_this = std::experimental::enable_shared_from_this<T>;
#else
# include <memory>
# include <functional>
  template <typename T>
  using enable_shared_from_this = std::enable_shared_from_this<T>;
#endif

#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <iostream>

struct A : enable_shared_from_this<A> {
  int a;
  A() : a(7) {}
  auto getptr() {
#ifdef CXX17
    return this->weak_from_this();
#else
    auto sptr = shared_from_this();
    auto wptr = std::weak_ptr<decltype(sptr)::element_type>(sptr);
    sptr.reset();  // Drop strong referencing
    return wptr;
#endif
  }
};

std::condition_variable condition;
std::mutex mutex;
std::atomic<bool> start0{false};
std::atomic<bool> start1{false};

std::shared_ptr<A> g_a;

static void thread_func0() {
  auto w_a = g_a->getptr();

  std::unique_lock<std::mutex> lock {mutex};
  condition.wait(lock, [&]() {
    return start0.load();
  });
  std::this_thread::sleep_for(std::chrono::microseconds(10));
  if (auto t = w_a.lock()) {
    std::cout << t->a << std::endl;
  }
}

static void thread_func1() {
  std::unique_lock<std::mutex> lock {mutex};
  condition.wait(lock, [&]() {
      return start1.load();
    });
  std::this_thread::sleep_for(std::chrono::microseconds(10000));
  g_a = nullptr;
}

int main() {
  g_a = std::make_shared<A>();

  std::thread thread0(thread_func0);
  std::thread thread1(thread_func1);

  start0 = true;
  start1 = true;
  condition.notify_all();

  thread0.join();
  thread1.join();

  return 0;
}

1 个答案:

答案 0 :(得分:3)

这是一个更简化的例子:

#include <experimental/memory>
#include <iostream>

template <typename T>
using enable_shared_from_this = std::experimental::enable_shared_from_this<T>;

struct A : enable_shared_from_this<A> {
  int a;
  A() : a(7) {}
};

int main() {
    auto sp = std::make_shared<A>();

    auto wp = sp->weak_from_this();
    if (auto s = wp.lock()) {
        std::cout << s->a << std::endl;
    }
}

这不会打印任何内容。为什么?原因最终是它为std::enable_shared_from_this而不是您自己可以提供的其他类型的原因:shared_ptr类需要选择加入此功能。新功能是实验性的,因此std::shared_ptr未选择加入 - 因此基础weak_ptr从未初始化。它只是没有发生,所以wp在这里始终是一个“空”weak_ptr

另一方面,std::experimental::shared_ptr 选择加入此功能。您需要使用与shared_ptr相对应的enable_shared_from_this - std::experimental::shared_ptr

没有std::experimental::make_shared(或者至少,据我所知),但选择加入机制并不是基于此 - 它只是基于任何shared_ptr构造。所以,如果你改变:

auto sp = std::make_shared<A>();

为:

auto sp = std::experimental::shared_ptr<A>(new A);

然后,选择加入机制与shared_ptr类型匹配并做正确的事情,您获得有效的weak_ptrstd::experimental::weak_ptr},lock()为您提供共享所有权基础A,程序打印7。