试想一下:
#include <boost/signals2.hpp>
#include <iostream>
struct object_with_slot
{
void operator()()
{
std::cout << "Slot called!" << std::endl;
member = 50500;
}
int member;
};
int main()
{
boost::signals2::signal<void ()> sig;
object_with_slot * ptr = new object_with_slot;
sig.connect(*ptr);
delete ptr;
sig();
}
输出是“叫老虎!” 并没有崩溃或任何东西。 这就是为什么我有几个问题:
1)为什么没有崩溃?
2)为什么有即使槽函数分配的东西对象不存在不崩溃?
3)如何让自动信号跟踪其槽的寿命是多少? 我的意思是,当槽被破坏,它就会断开。
问题3号是最重要的,因为我需要实现观察者模式,而且往往观察员(槽)一辈子都不会是静态的(对于整个时间的应用程序运行时)。
1)你是幸运的。 如果没有,你会得到一个分段错误。
2)存储器为不以任何方式被覆盖。
3)你可以使用插槽::跟踪,当跟踪对象被删除自动断开。 Boost.Signals2可以跟踪由升压:: shared_ptr的管理对象。
#include <boost/signals2.hpp>
#include <boost/shared_ptr.hpp>
struct object_with_slot
{
void operator()()
{
std::cout << "Slot called!" << std::endl;
member = 50500;
}
int member;
};
//
int main()
{
typedef boost::signals2::signal<void ()> sig_type;
sig_type sig;
{
boost::shared_ptr<object_with_slot> ptr(new object_with_slot);
sig.connect(sig_type::slot_type(*ptr).track(ptr));
// 'object_with_slot' managed by ptr is destroyed
}
sig(); // 'object_with_slot' not called here.
return 0;
}
更新:
添加代码,用于跟踪的std :: shared_ptr的和std :: weak_ptr的对象:
#include <memory>
#include <boost/signals2.hpp>
// added specializations for std::weak_ptr and std::shared_ptr
namespace boost
{
namespace signals2
{
template<typename T> struct weak_ptr_traits<std::weak_ptr<T> >
{
typedef std::shared_ptr<T> shared_type;
};
template<typename T> struct shared_ptr_traits<std::shared_ptr<T> >
{
typedef std::weak_ptr<T> weak_type;
};
}
}
struct object_with_slot
{
void operator()()
{
std::cout << "Slot called!" << std::endl;
member = 50500;
}
int member;
};
//
int main()
{
typedef boost::signals2::signal<void ()> sig_type;
sig_type sig;
std::shared_ptr<object_with_slot> ptr(new object_with_slot);
sig.connect(sig_type::slot_type(*ptr).track_foreign(ptr)); // ptr is tracked
sig();
return 0;
}
图1和2)事实上,它是一个未定义的行为。 您所使用的引用操作,现在连有object_with_slot的价值,它的地址是免费的内存管理器分配给任何其他进程。 巧合的是它仍然是一个“有效地址”。 和PTR自由分配给无故内存泄漏任何其他值。
尝试这样的事情,你会看到,每次爆炸
#include <boost/signals2.hpp>
#include <iostream>
struct object_with_slot
{
object_with_slot()
{
member = new int(10);
}
~object_with_slot()
{
delete member; //comment this line and everything works again
}
void operator()()
{
std::cout << "Slot called!" << std::endl;
*member = 50500; //it was destroyed above
}
int *member;
};
int main()
{
boost::signals2::signal<void ()> sig;
object_with_slot * ptr = new object_with_slot;
sig.connect(*ptr);
delete ptr;
ptr = 0x0;
sig();
}
3)你可以把object_with_slot的析构函数的另一个信号,那么它可以通知时,它被调用。
很危险的例子中给出。 看一看:
#include <iostream>
#include <memory>
#include <boost/signals2.hpp>
struct object_with_slot
{
object_with_slot() {
std::cout << "ctor\n";
}
object_with_slot(const object_with_slot &) {
std::cout << "cctor\n";
}
~object_with_slot() {
std::cout << "dtor\n";
}
void operator()()
{
std::cout << "Slot called!" << std::endl;
member = 50500;
}
int member;
};
//
int main()
{
typedef boost::signals2::signal<void ()> sig_type;
sig_type sig;
std::shared_ptr<object_with_slot> ptr(new object_with_slot);
sig.connect(sig_type::slot_type(*ptr).track_foreign(ptr)); // ptr is tracked
sig();
return 0;
}
您如何看待,有什么了这段代码(G ++ 4.8.1,libboost 1.54)?
ctor
cctor
cctor
cctor
cctor
cctor
cctor
cctor
cctor
dtor
dtor
dtor
dtor
dtor
cctor
dtor
cctor
dtor
dtor
dtor
cctor
dtor
Slot called!
dtor
dtor
我不认为,这种行为预期。 因为我们传递的副本(按价值计算) *ptr
(实例object_with_slot
)的connect
方法。 它可能会解决,例如,通过引用包装:
sig.connect(sig_type::slot_type(boost::ref(*ptr)).track_foreign(ptr)); // ptr is tracked
小心模板和类型。