Использование boost :: signal2 :: trackable с лямбдами

Я использую шаблон, подобный этому, C ++ 11:

class FooViewController {
void build() {
auto label = ...

network->doWork([] (const Result& r) {
label->setText(r.text);
});
}
}

FooViewController может быть деконструирован до doWork завершается, вызывая сбои. Глядя на boost :: сигналы2, я думаю об использовании boost::signals2::trackable, который отлично подходит для моих однопоточных целей, с тем преимуществом, что мне не нужно хранить и управлять своими подключениями напрямую, однако я не уверен, как заставить такое решение работать с лямбдами.

Вот рабочая лямбда-бесплатная версия:

class Foo : public boost::signals2::trackable {
public:
void bar() {
printf("Fire!");
}
};Usage:

boost::signals2::signal<void()> signal;
{
Foo test;
signal.connect(boost::bind(&Foo::bar, &test));
signal();
}
signal();

Output:

Fired!
// Note a second 'Fired!' did not occur, which is correct behavior

Две цели:

1— Я хотел бы сделать что-то вроде:

signal.connect(boost::bind([] {
printf("Fired!");
}, &test));

Который НЕ назвал бы лямбду после test сносится.

2— Я не хочу напрямую управлять объектами подключения, возвращенными .connect,

1

Решение

Как можно заметить Вот: «Использование отслеживаемого класса не рекомендуется для нового кода»

Возможно, решите пойти с scoped_connection или же track вместо.

Пример:

#include <iostream>
#include <memory>

#include <boost/signals2.hpp>struct short_lived : public boost::signals2::scoped_connection {
public:
short_lived(const boost::signals2::connection &conn) : boost::signals2::scoped_connection{conn}
{   }
~short_lived() {
std::cout << "I'm dying...1!" << std::endl;
}

};

int main() {
typedef boost::signals2::signal<void()> sig_type;
sig_type s1;

{
/* boost::signals2::scoped_connection */ short_lived conn{s1.connect([]() {
std::cout << "Fire1!" << std::endl;
})};
s1();
}
s1();
std::cout << std::endl;

{
auto lam = []() {
std::cout << "Fire2!" << std::endl;
};

/* shared_ptr with custom deleter that does not delete (since we didn't use new),
but prints a message */
std::shared_ptr<decltype(lam)> sptr{&lam, [](decltype(lam) *) { std::cout << "I'm dying...2!" << std::endl; }};
s1.connect(sig_type::slot_type(lam).track_foreign(sptr));
s1();
}
s1();

return 0;
}

http://melpon.org/wandbox/permlink/c8LHGIp8ArkKsnWA

1

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

Вы можете кодировать что-то подобное, используя общие / слабые указатели:

Жить на Колиру

#include <boost/signals2.hpp>
#include <boost/make_shared.hpp>
#include <boost/weak_ptr.hpp>
#include <iostream>

class Foo : public boost::signals2::trackable {
public:
void bar() {
printf("Fire!\n");
}
};

int main() {
boost::signals2::signal<void()> signal;
{
auto test = boost::make_shared<Foo>();

signal.connect([wp = boost::weak_ptr<Foo>(test)]
{
if (auto sp = wp.lock())
sp->bar();
else
std::cout << "expired\n";
}
);

signal();
}
signal();
}

Печать

Fire!
expired

Строго версия C ++ 11: Жить на Колиру

0

Нашел ответ ссылаясь trackable_test.cpp:

struct short_lived : public boost::signals2::trackable {
~short_lived() {
cout << "I'm dying...!" << std::endl;
}
};

void main() {
typedef boost::signals2::signal<void()> sig_type;
sig_type s1;

short_lived* shorty = new short_lived();
s1.connect(boost::bind<void>([](const short_lived*) {
cout << "Fire!" << std::endl;
}, shorty));
s1();
delete shorty;

s1();
}

Выход

Fire!
I'm dying...!

…и пример с несколькими параметрами (boost :: bind refresher):

typedef boost::signals2::signal<void(int)> sig_type;

// ...same...

s1.connect(boost::bind<void>([](const short_lived*, int cannon) {
cout << "Fire " << cannon << "!" << std::endl;
}, shorty, _1));
s(1);
delete shorty;
s(2);

Выход

Fire 1!
I'm dying...!
0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector