Boost库可谓博大精深,很多思想都很前卫或者说奇特,至少在我们实际的应用软件开发中,很少能够用到其中的思想,大部分也就是简单的类库调用,仅此而已。
大致上看了一下signal的实现,感觉里面的东西确实很复杂,为了以后更清晰的了解,运用,提高自己的技术水平,针对signal中的slot相关部分进行代码剖析,以备后用。
实例代码:
#include "stdafx.h"
#include "boost/signal.hpp"
#include "boost/bind.hpp"
#include "boost/ref.hpp"
#include <iostream>
using namespace std;
struct s1 : boost::signals::trackable
{
};
struct s2 : boost::signals::trackable
{
};
void Test_one(s1& test1, s2& test2)
{
cout <<"This is my first look up the signal" <<endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
s1 t1;
s2 t2;
boost::signal<void(s1, s2) > sig;
sig.connect(boost::bind(&Test_one, boost::ref(t1), boost::ref(t2)));
return 0;
}
以上代码中,当执行到sig.connect时,背后的强大引擎便被开启:
signal::connect(const slot_type& in_slot,
BOOST_SIGNALS_NAMESPACE::connect_position at)
由于connect需要一个slot类型(slot_type是signal中的一个typedef,原类型即为slot),这时,面对一函数对象,便进行了一次类型转换,于是开始了本篇内容的赘述:
C:/Documents and Settings/Administrator/桌面/signals analyze/1.jpg
图一 Slot类图
Slot的构造函数:
slot(const F& f) : slot_function(BOOST_SIGNALS_NAMESPACE::get_invocable_slot(f, BOOST_SIGNALS_NAMESPACE::tag_type(f)))
{
this->data.reset(new data_t);
BOOST_SIGNALS_NAMESPACE::detail::bound_objects_visitor
do_bind(this->data->bound_objects);
visit_each(do_bind,
BOOST_SIGNALS_NAMESPACE::get_inspectable_slot
(f, BOOST_SIGNALS_NAMESPACE::tag_type(f)));
create_connection();
}
//这里,构造了一个dat_t对象见图一,用来记录trackable对象,以及记录一个connection对象的副本,具体如何被记录的,请慢慢往下看。
首先,visit_each会将bind对象中的可跟踪对象包括参数(即继承自trackable类)收集起来,放在了data结构中的bound_objects。具体它是怎么获得,可以根据实例代码调试追踪即可看到源码的实现。于是,bound_objects中记录了s1和s2所对应的对象的指针。要干什么用,见后文分析。
再后来,重量级的函数 create_connection函数出场了。
create_connection();
不看源码,先猜猜它要干什么,应该是建立一个连接,记录一些信息,以备后用。果真如此吗?
图二 connection类结构
代码片段一:
void slot_base::create_connection()
{
basic_connection* con = new basic_connection();
con->signal = static_cast<void*>(this);
con->signal_data = 0;
con->blocked_ = false ;
con->signal_disconnect = &bound_object_destructed;
data->watch_bound_objects.reset(con);
这里先new了一个连接,设置其成员,并设置slot成员变量 data->watch_bound_objects保存该con。
图三 trackable类结构
代码片段二(参考图二和图三)
scoped_connection safe_connection(data->watch_bound_objects);
for(std::vector<const trackable*>::iterator i =
data->bound_objects.begin();
i != data->bound_objects.end(); ++i) {
BOOST_SIGNALS_NAMESPACE::detail::bound_object binding;
(*i)->signal_connected(data->watch_bound_objects, binding);
con->bound_objects.push_back(binding);
遍历data->bound_objects(见图一),然后就追溯到trackable的signal_coonected函数中了
void trackable::signal_connected(connection c,
bound_object& binding) const
{
// Insert the connection
connection_iterator pos =
connected_signals.insert(connected_signals.end(), c);
// Make this copy of the object disconnect when destroyed
pos->set_controlling();
binding.obj = const_cast<void*>(reinterpret_cast<const void*>(this));//trackable对象
binding.data = reinterpret_cast<void*>(new connection_iterator(pos));
binding.disconnect = &signal_disconnected;
}
这里其实是为了解决某一个trackable对象同时被多个signal记录并进行追踪的情况。该函数作了两个工作,1)将连接记录到trackable中,2)填充bound_object对象,该对象被记录在了新建的连接con中。
综上所述:
可以看到,trackable中记录了该次连接,如果trackable对象被析构了,那么可以找到该连接,并将其断开。
详细的内容大家可以参考一下:http//bolg.csdn.net/pongba好多内容分析的很是经典。