首页 > 解决方案 > boost::signals2: 连接到不同类的插槽

问题描述

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

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

如果信号是由某个函数触发的,我不想调用“OtherClass”的成员(pointer_M 指向的),而是“Solid”的成员,即刚刚初始化 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 非常缺乏经验。

最好的

标签: c++boostsignals2

解决方案


但这就是我想要实现的目标吗?

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

所以让我为你编造你的“虚拟代码”。我将回避您在该行中显示的巨大的类型过度复杂性:

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

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

住在科利鲁

#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

水晶球:我们能猜出问题吗?

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

正确的终身管理

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

住在科利鲁

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

简化

在您的情况下, theOtherClass已经由 the 拥有Solid(至少它是创建的)。似乎根本不需要共享指针:

住在科利鲁

#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实际上需要共享,那么您可能想要跟踪指针。Solid您可能也应该考虑制作enable_shared_from_this. 如果您想成为真正的“企业级工程师™”,您也许可以对别名构造函数做一些花哨的事情:shared_ptr 的别名构造函数是干什么用的?


推荐阅读