Слабое связывание с использованием 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;
}

2

Решение

Вот более упрощенный пример:

#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.

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]