考虑一下:
#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();
}
输出是“Slot called!”没有崩溃或任何事情。这就是我有几个问题的原因:
1)为什么没有崩溃?
2)为什么即使插槽功能分配给不存在的对象也没有崩溃?
3)如何让信号自动跟踪其插槽的使用寿命?我的意思是当插槽被破坏时,它会断开连接。
问题3是最重要的,因为我需要实现观察者模式,并且观察者(插槽)的生命周期通常不会是静态的(在应用程序运行的整个时间)。
答案 0 :(得分:3)
1)你很幸运。如果没有,您将遇到分段错误。
2)记忆没有以任何方式被覆盖。
3)您可以使用slot :: track在被删除跟踪对象时自动断开连接。 Boost.Signals2可以跟踪由boost :: 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 :(得分:1)
1和2)实际上它是一种未定义的行为。您使用了dereference运算符,现在connect具有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的析构函数上放置另一个信号,然后它可以在被调用时通知。
答案 2 :(得分:0)
给出了非常危险的例子。看看:
#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
小心模板和类型。