如何使C++增强::信号从封装发出它的物体的物体中捕获

How to make a C++ boost::signal be caught from an object which encapsulates the object which emits it?

本文关键字:C++ 何使 增强 信号 封装      更新时间:2023-10-16

我有一个TcpDevice类,它封装了一个TCP连接,它有一个onRemoteDisconnect 方法,每当远程端挂断时就会被调用。然后,有一个 SessionManager 对象,该对象创建 TcpSession 对象,这些对象将 TcpDevice 作为通信通道,并将它们插入内部指针容器中供应用程序使用。如果任何托管 TcpSession 应该结束,我希望 SessionManager 实例收到有关它的通知,然后从容器中删除相应的会话,从而释放与其关联的资源。

发现我的问题与这个问题非常相似:

对象从容器中删除自身

但是由于他有一个用于检查连接状态的线程,它与我的以及我打算使用 boost::signals 解决它的方式略有不同,所以我决定去找一个针对它的新问题 - 如果这是错误的方法,我深表歉意......我仍然对如何正确使用SO:)有所了解

由于我对QT信号/插槽有点熟悉,我发现boost::signals提供了类似的机制(我已经在使用boost:asio并且在这个项目中没有QT),所以我决定实现一个remoteDevice断开连接的信号由TcpDevice的onRemoteDisconnect发出,并且我将在SessionManager中有一个插槽。,然后从容器中删除断开连接的会话和设备。

为了初步尝试,我在tcpdevice.hpp中将信号声明为TcpDevice的公共成员:

class TcpDevice
{
             (...)
  public:
    boost::signal <void ()> remoteDeviceDisconnected;
             (...)
}

然后我从TcpDevice的onRemoteConnect方法发出它,如下所示:

remoteDeviceDisconnected();

现在,有没有办法从会话管理器内部将此信号连接到我的会话管理器插槽?我试过这个:

unsigned int SessionManager::createSession(TcpDevice* device)
{
  unsigned int session_id = session_counter++;
  boost::mutex::scoped_lock lock(sessions_mutex);
  sessions.push_back(new TcpSession(device, session_id));
  device->remoteDeviceDisconnected.connect(boost::bind(&SessionManager::removeDeadSessionSlot, this));
  return session_id;
}

编译得很好,但在链接时它抱怨远程设备的多个定义在几个目标代码文件中断开连接

tcpsession.cpp.o:(.bss+0x0): multiple definition of `remoteDeviceDisconnected'
tcpdevice.cpp.o: (.bss+0x0): first defined here
sessionmanager.cpp.o:(.bss+0x0): multiple definition of `remoteDeviceDisconnected'
tcpdevice.cpp.o: (.bss+0x0): first defined here

我觉得这很奇怪,因为我没有在任何地方重新定义信号,而只是在上面的createSession方法中使用它。

任何提示将不胜感激!谢谢!

我的坏!就像我们都应该期待的那样,链接器是对的......确实有第二个定义,我只是无法立即发现它,因为它不是由我的任何类定义的,而只是"浮动"在我的一个.cpp文件周围,就像在 boost::signals 示例中找到的那些一样。

只是为了记录,最初的想法就像一个魅力:当给定的TcpDevice与远程端断开连接时,它会发出remoteDevice断开连接的信号,然后由SessionManager对象捕获,该对象保存指向该TcpDevice的TcpSession实例。收到通知后,SessionManager 的方法removeDeadSessionSlot 将执行,遍历容器ptr_list会话并删除断开连接的会话:

void SessionManager::removeDeadSessionSlot()
{
  boost::mutex::scoped_lock lock(sessions_mutex);
  TcpSession_ptr_list_it it = sessions.begin();
  while (it != sessions.end()) {
    if (!(*it).device->isConnected())
      it = sessions.erase(it);
    else
      ++it;
  }
}

希望这可以作为某人的参考!