boost::signals2: 连接到不同 class 的插槽

boost::signals2: connect to a slot of a diffeent class

我正在尝试在我的程序中使用 boost::signals2 功能。 在我的名为“Solid”的“Main Class”中,我有一个成员在构造函数体内初始化(因此 成员初始化列表之后),如下所示:

pointer_M = boost::make_shared<OtherClass>(/*parameters,...*/);

如果信号由某个函数触发,我不想调用“OtherClass”的成员(pointer_M 指向),而是调用“Solid”的成员,即class 刚刚初始化 pointer_M。

我尝试了以下方法:

 boost::signals2::connection tria_signal = /*...*/.connect( boost::signals2::signal<void()>::slot_type(&Solid::call_this_function, pointer_M.get()).track(pointer_M) );

"call_this_function" 是 Solid 的成员函数。不幸的是有一堆错误信息。 “OtherClass”和“Solid”没有继承关系。

由于我对 boost 非常缺乏经验,因此我希望能得到一些如何解决我的问题的建议。

最佳

But is that what I am trying to achieve possible at all?

关键是,如果没有更清晰的描述,我们就无法分辨。这听起来很简单:信号专门用于解耦呼叫者和被呼叫者。

所以让我为您补充 。我将回避您在该行中显示的巨大的类型过度复杂化:

boost::signals2::connection tria_signal =
/*...*/.connect(boost::signals2::signal<void()>::slot_type(
                &Solid::call_this_function, pointer_M.get())
                .track(pointer_M));

插槽的整体思想是它们使用类型擦除来泛化可调用对象。只需以任何兼容形式提供您的可调用对象,让库推断出神秘的实现类型。

Live On Coliru

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

struct OtherClass {
    OtherClass(...) {}

    boost::signals2::signal<void()> tria;

    void test() {
        if (!tria.empty())
            tria();
    }
};

struct Solid {
    boost::shared_ptr<OtherClass> pointer_M;

    Solid() {
        pointer_M = boost::make_shared<OtherClass>(1,2,3);
        auto tria_signal = pointer_M->tria.connect(
            boost::bind(&Solid::call_this_function, this));
    }

  private:
    void call_this_function() {
        std::cout << "Solid was here" << std::endl;
    };
};

int main() {
    Solid s;
    s.pointer_M->test();
}

版画

Solid was here

Crystal Ball:我们能猜出问题所在吗?

也许我们可以猜到问题所在:看起来您正在努力跟踪 pointer_M 指向的对象的生命周期。这没有用,因为 OtherClass 首先拥有信号,这意味着当 OtherClass 消失时所有连接都会断开。

正确的生命周期管理

您可能希望在 Solid 对象的生命周期结束时断开连接,而不是 OtherClass。一般来说,我建议在这里使用 scoped_connection

Live On Coliru

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

struct OtherClass {
    OtherClass(...) {}

    boost::signals2::signal<void()> tria;

    void test() {
        if (!tria.empty())
            tria();
    }
};

struct Solid {
    boost::shared_ptr<OtherClass> pointer_M;

    Solid() {
        pointer_M = boost::make_shared<OtherClass>(1,2,3);
        tria_signal = pointer_M->tria.connect(
            boost::bind(&Solid::call_this_function, this));
    }

  private:
    boost::signals2::scoped_connection tria_signal;

    void call_this_function() {
        std::cout << "Solid was here" << std::endl;
    };
};

int main() {
    boost::shared_ptr<OtherClass> keep;
    {
        Solid s;
        std::cout << "Testing once:" << std::endl;
        s.pointer_M->test();

        keep = s.pointer_M; // keep the OtherClass alive
    } // destructs Solid s

    std::cout << "Testing again:" << std::endl;
    keep->test(); // no longer connected, due to scoped_connection
}

版画

Testing once:
Solid was here
Testing again:

简化

在你的例子中,OtherClass 已经被 Solid 拥有(至少它是创建的)。似乎在这里根本不需要共享指针:

Live On Coliru

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

struct OtherClass {
    OtherClass(...) {}

    boost::signals2::signal<void()> tria;

    void test() {
        if (!tria.empty())
            tria();
    }
};

struct Solid {
    Solid() : oc_M(1,2,3) {
        tria_signal = oc_M.tria.connect(
            boost::bind(&Solid::call_this_function, this));
    }

    void test() { oc_M.test(); }

  private:
    OtherClass oc_M;
    boost::signals2::scoped_connection tria_signal;

    void call_this_function() {
        std::cout << "Solid was here" << std::endl;
    };
};

int main() {
    Solid s;
    s.test();
}

因为成员是按照声明的相反顺序销毁的,所以这是完全安全的。

建筑宇航

如果您知道自己在做什么,并且 pointer_M 实际上需要共享,那么您可能想要跟踪 that 指针。您可能应该考虑将 Solid 也设为 enable_shared_from_this。如果您想成为真正的“Enterprise Grade Engineer™”,您或许可以使用别名构造函数做一些花哨的事情:What is shared_ptr's aliasing constructor for?