本文介绍了如何使一个C ++ boost :: signal从一个对象封装的对象发出它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我发现我的问题非常类似于这个问题:





但由于他有一个线程用于检查连接状态,它有点不同于我和我打算使用 boost :: signals 解决它的方式,所以我决定去一个新的问题面向它 - 我道歉,如果它是错误的方式做它...我仍然得到如何正确使用SO的感觉:)



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



要初始尝试一下,我在 tcpdevice.hpp 中声明该信号是 TcpDevice 的公共成员:

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

> TcpDevice的 onRemoteDisconnect方法:

  remoteDeviceDisconnected 

现在,有没有办法将此信号连接到我的 SessionManager 会话管理器?我尝试这样:

  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;
}

它编译正常,但在链接时它抱怨多个定义 remoteDeviceDisconnected 在多个目标代码文件中:

  tcpsession.cpp.o :(。bss + 0x0):multiple definition 'remoteDeviceDisconnected'
tcpdevice.cpp.o:(.bss + 0x0):首先在这里定义
sessionmanager.cpp.o :( .bss + 0x0):`remoteDeviceDisconnected'的多个定义
tcpdevice.cpp.o:(.bss + 0x0):首先在这里定义

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



任何提示将非常感谢!谢谢!

解决方案

我的错!像我们所有应该期望的,链接器是正确的......有确实第二个定义,我只是不能立即发现它,因为它没有被我的任何类定义,但只是浮动我的一个.cpp文件,例如。



只是为了记录,最初的想法像一个魅力:当给定的 TcpDevice 与远程端断开连接时,它会发出 remoteDeviceDisconnected 信号,然后由 SessionManager 对象捕获,该对象持有 TcpSession 实例指向 TcpDevice 。一旦通知,会话管理器方法 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
else
++ it;
}
}

希望可以作为对某人的参考! / p>

I have a TcpDevice class which encapsulates a TCP connection, which has an onRemoteDisconnect method which gets called whenever the remote end hangs up. Then, there's a SessionManager object which creates TcpSession objects which take a TcpDevice as a communication channel and inserts them in an internal pointer container for the application to use. In case any of the managed TcpSessions should end, I would like the SessionManager instance to be notified about it and then remove the corresponding session from the container, freeing up the resources associated with it.

I found my problem to be very similar to this question:

Object delete itself from container

but since he has a thread for checking the connections state, it gets a little different from mine and the way I intended to solve it using boost::signals, so I decided to go for a new question geared towards it - I apologize if it's the wrong way to do it... I'm still getting the feel on how to properly use S.O. :)

Since I'm kind of familiar with QT signals/slots, I found boost::signals offers a similar mechanism (I'm already using boost::asio and have no QT in this project), so I decided to implement a remoteDeviceDisconnected signal to be emitted by TcpDevice's onRemoteDisconnect, and for which I would have a slot in SessionManager, which would then delete the disconnected session and device from the container.

To initially try it out I declared the signal as a public member of TcpDevice in tcpdevice.hpp:

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

Then I emitted it from TcpDevice's onRemoteDisconnect method like this:

remoteDeviceDisconnected();

Now, is there any way to connect this signal to my SessionManager slot from inside session manager? I tried this:

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;
}

It compiles fine but at link time it complains of multiple definitions of remoteDeviceDisconnected in several object code files:

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

I found this strange, since I didn't redefine the signal anywhere, but just used it at the createSession method above.

Any tips would be greatly appreciated! Thank you!

解决方案

My bad! Like we all should expect, the linker was right... there was indeed a second definition, I just couldn't spot it right away because it wasn't defined by any of my classes, but just "floating" around one of my .cpp files, like those found on boost::signals examples.

Just for the record, the initial idea worked like a charm: when a given TcpDevice gets disconnected from the remote end, it emits the remoteDeviceDisconnected signal, which is then caught by the SessionManager object which holds the TcpSession instance that points to that TcpDevice. Once notified, SessionManager's method removeDeadSessionSlot gets executed, iterating through the sessions ptr_list container and removing the one which was disconnected:

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;
  }
}

Hope that may serve as a reference to somebody!

这篇关于如何使一个C ++ boost :: signal从一个对象封装的对象发出它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 07:25