使用 c++17 的弱绑定
Weak binding using c++17
我正在开发一个处理框架,其中将回调注册到事件,并确保不会在已删除的对象上调用回调,我想使用弱捕获而不是通过引用捕获。使用 C++14
和 shared_from_this()
使这项工作没问题,但是如何使用 C++17
和 weak_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;
}
这里有一个更简化的例子:
#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
class 需要选择加入此功能。新功能是实验性的,因此 std::shared_ptr
未选择加入 - 因此基础 weak_ptr
从未初始化。它只是没有发生,所以 wp
在这里总是 "empty" weak_ptr
。
另一方面,std::experimental::shared_ptr
选择加入此功能。您需要使用对应于您的 enable_shared_from_this
的 shared_ptr
- 即 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_ptr
(一个 std::experimental::weak_ptr
),lock()
给你底层 A
的共享所有权,程序打印 7.
我正在开发一个处理框架,其中将回调注册到事件,并确保不会在已删除的对象上调用回调,我想使用弱捕获而不是通过引用捕获。使用 C++14
和 shared_from_this()
使这项工作没问题,但是如何使用 C++17
和 weak_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;
}
这里有一个更简化的例子:
#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
class 需要选择加入此功能。新功能是实验性的,因此 std::shared_ptr
未选择加入 - 因此基础 weak_ptr
从未初始化。它只是没有发生,所以 wp
在这里总是 "empty" weak_ptr
。
另一方面,std::experimental::shared_ptr
选择加入此功能。您需要使用对应于您的 enable_shared_from_this
的 shared_ptr
- 即 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_ptr
(一个 std::experimental::weak_ptr
),lock()
给你底层 A
的共享所有权,程序打印 7.