简体   繁体   English

使用C ++ 17的弱绑定

[英]Weak binding using c++17

I am working on a processing framework where callbacks are registered to events and to ensure that no callback is invoked on an object, which has been deleted, I would like to use weak capture rather than capture by reference. 我正在处理一个处理框架,在该框架中将回调注册到事件中,并确保没有对已删除的对象调用任何回调,我想使用弱捕获而不是通过引用捕获。 It was no problem to make this work using C++14 and shared_from_this() , but how is this correctly achieved using C++17 and weak_from_this() . 这是没有问题的使用这项工作,使C++14shared_from_this()这是怎么回事使用正确实现C++17weak_from_this()

The example below prints nothing when C++17 is used. 使用C++17时,以下示例不显示任何内容。 I am using g++ 6.3.0-18 我正在使用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;
}

Here's a way more reduced example: 这是一个更简化的示例:

#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;
    }
}

This prints nothing. 这不会打印任何内容。 Why? 为什么? The reason is ultimately the reason why it's std::enable_shared_from_this and not some other type that you yourself can provide: the shared_ptr class needs to opt-in to this functionality. 原因最终是它为什么是std::enable_shared_from_this而不是您自己可以提供的其他类型的原因: shared_ptr类需要选择加入此功能。 The new functionality is experimental, so std::shared_ptr was not opting in - so the underlying weak_ptr was never initialized. 新功能是实验性的,因此没有选择std::shared_ptr因此根本没有初始化底层的weak_ptr It just doesn't happen, so wp is always an "empty" weak_ptr here. 只是没有发生,因此wp在这里始终是“空” weak_ptr

On the other hand, std::experimental::shared_ptr does opt-in to this functionality. 另一方面, std::experimental::shared_ptr 确实选择加入此功能。 You need to use the shared_ptr corresponding to your enable_shared_from_this - which is std::experimental::shared_ptr . 您需要使用与您的enable_shared_from_this对应的shared_ptr这是std::experimental::shared_ptr

There's no std::experimental::make_shared (or at least, as far as I could find), but the opt-in mechanism isn't based on that anyway - it's just based on any shared_ptr construction. 没有std::experimental::make_shared (至少,据我所知),但是无论如何,选择加入机制都不基于此-它只是基于任何shared_ptr构造。 So if you change: 因此,如果您更改:

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

to: 至:

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

Then the opt-in mechanism matches the shared_ptr type and does the right thing, you get a valid weak_ptr (a std::experimental::weak_ptr ), lock() gives you shared ownership of the underlying A , and the program prints 7. 然后选择加入机制匹配shared_ptr类型并执行正确的操作,您将获得有效的weak_ptr (一个std::experimental::weak_ptr ), lock()为您提供基础A共享所有权,程序将输出7。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM