以下代碼出自陳碩,是一個信號的槽的實現(xiàn)然磷。
#define _CRT_SECURE_NO_WARNINGS
#include <functional>
#include <iostream>
#include <memory>
#include <vector>
#include <algorithm>
#include <string>
#include <cassert>
#include <stdio.h>
using namespace std;
template<typename Signature>
class SignalTrivial;
using placeholders::_1;
using placeholders::_2;
template<typename Callback>
struct SlotImpl;
template<typename Callback>
struct SignalImpl
{
typedef std::vector<weak_ptr<SlotImpl<Callback> > > SlotList;
SignalImpl()
: slots_(new SlotList)
{
}
void copyOnWrite()
{
//mutex_.assertLocked();
if (!slots_.unique())
{
slots_.reset(new SlotList(*slots_));
}
assert(slots_.unique());
}
void clean()
{
//MutexLockGuard lock(mutex_);
copyOnWrite();
SlotList& list(*slots_);
typename SlotList::iterator it(list.begin());
while (it != list.end())
{
if (it->expired())
{
it = list.erase(it);
}
else
{
++it;
}
}
}
//MutexLock mutex_;
shared_ptr<SlotList> slots_;
};
template<typename Callback>
struct SlotImpl
{
typedef SignalImpl<Callback> Data;
SlotImpl(const shared_ptr<Data>& data, Callback&& cb)
: data_(data), cb_(cb), tie_(), tied_(false)
{
}
SlotImpl(const shared_ptr<Data>& data, Callback&& cb,
const shared_ptr<void>& tie)
: data_(data), cb_(cb), tie_(tie), tied_(true)
{
}
~SlotImpl()
{
printf("~SlotImpl\n");
shared_ptr<Data> data(data_.lock());
if (data)
{
data->clean();
}
}
weak_ptr<Data> data_;
Callback cb_;
weak_ptr<void> tie_;
bool tied_;
};
/// This is the handle for a slot
///
/// The slot will remain connected to the signal fot the life time of the
/// returned Slot object (and its copies).
typedef shared_ptr<void> Slot;
template<typename Signature>
class Signal;
template <typename RET, typename... ARGS>
class Signal<RET(ARGS...)>
{
public:
typedef std::function<void(ARGS...)> Callback;
typedef SignalImpl<Callback> SignalImpl;
typedef SlotImpl<Callback> SlotImpl;
Signal()
: impl_(new SignalImpl)
{
}
~Signal()
{
}
// connect 其實為寫shared_ptr<SignalImpl> impl_.slots_;
Slot connect(Callback&& func)
{
shared_ptr<SlotImpl> slotImpl(
new SlotImpl(impl_, std::forward<Callback>(func)));
add(slotImpl);
return slotImpl;
}
Slot connect(Callback&& func, const shared_ptr<void>& tie)
{
shared_ptr<SlotImpl> slotImpl(new SlotImpl(impl_, func, tie));
add(slotImpl);
return slotImpl;
}
// call 其實為讀shared_ptr<SignalImpl> impl_.slots_;
void call(ARGS&&... args)
{
SignalImpl& impl(*impl_);
shared_ptr<typename SignalImpl::SlotList> slots;
{
//MutexLockGuard lock(impl.mutex_);
slots = impl.slots_; // 防止寫這塊內(nèi)存;
}
typename SignalImpl::SlotList& s(*slots);
for (typename SignalImpl::SlotList::const_iterator it = s.begin(); it != s.end(); ++it)
{
shared_ptr<SlotImpl> slotImpl = it->lock();
if (slotImpl)
{
shared_ptr<void> guard;
if (slotImpl->tied_)
{
guard = slotImpl->tie_.lock();
if (guard)
{
slotImpl->cb_(args...);
}
}
else
{
slotImpl->cb_(args...);
}
}
}
}
private:
void add(const shared_ptr<SlotImpl>& slot)
{
SignalImpl& impl(*impl_);
{
//MutexLockGuard lock(impl.mutex_);
//impl.copyOnWrite();
impl.slots_->push_back(slot);
}
}
const shared_ptr<SignalImpl> impl_;
};
class String
{
public:
String(const char* str)
{
printf("String ctor this %p\n", this);
}
String(const String& rhs)
{
printf("String copy ctor this %p, rhs %p\n", this, &rhs);
}
String(String&& rhs)
{
printf("String move ctor this %p, rhs %p\n", this, &rhs);
}
};
class Foo
{
public:
~Foo(){
i = 0;
printf("~Foo()\n");
}
void zero();
void zeroc() const;
void one(int);
void oner(int&);
void onec(int) const;
void oneString(const String& str);
// void oneStringRR(String&& str);
static void szero();
static void sone(int);
static void soneString(const String& str);
private:
int i = 2;
};
void Foo::zero()
{
++i;
printf("Foo::zero() = %d\n",i);
}
void Foo::zeroc() const
{
printf("Foo::zeroc()\n");
}
void Foo::szero()
{
printf("Foo::szero()\n");
}
void Foo::one(int x)
{
printf("Foo::one() x=%d\n", x);
}
void Foo::onec(int x) const
{
printf("Foo::onec() x=%d\n", x);
}
void Foo::sone(int x)
{
printf("Foo::sone() x=%d\n", x);
}
void Foo::oneString(const String& str)
{
printf("Foo::oneString\n");
}
void Foo::soneString(const String& str)
{
printf("Foo::soneString\n");
}
void testSignalSlotZero()
{
Signal<void()> signal;
printf("==== testSignalSlotZero ====\n");
signal.call();
Slot s1 = signal.connect(&Foo::szero);
printf("========\n");
signal.call();
Foo f;
Slot s2 = signal.connect(bind(&Foo::zero, &f));
printf("========\n");
signal.call();
Slot s3 = signal.connect(bind(&Foo::one, &f, 42));
printf("========\n");
signal.call();
const Foo cf;
Slot s4 = signal.connect(bind(&Foo::zeroc, &cf));
printf("========\n");
signal.call();
Slot s5 = signal.connect(bind(&Foo::onec, &cf, 128));
printf("========\n");
signal.call();
s1 = Slot();
printf("========\n");
signal.call();
s4 = s3 = s2 = Slot();
printf("========\n");
signal.call();
}
void testSignalSlotOne()
{
Signal<void(int)> signal;
printf("========\n");
signal.call(50);
Slot s4;
{
Slot s1 = signal.connect(&Foo::sone);
printf("========\n");
signal.call(51);
Foo f;
Slot s2 = signal.connect(bind(&Foo::one, &f, _1));
printf("========\n");
signal.call(52);
const Foo cf;
Slot s3 = signal.connect(bind(&Foo::onec, &cf, _1));
printf("========\n");
signal.call(53);
s4 = s3;
}
printf("========\n");
signal.call(54);
}
void testSignalSlotLife()
{
Slot s1;
{
Signal<void()> signal;
signal.connect(&Foo::szero);
printf("========\n");
signal.call();
Foo f;
function<void()> func = bind(&Foo::zero, &f);
s1 = signal.connect(bind(&Foo::zero, &f));
printf("========\n");
signal.call();
}
}
Signal<void(int)> signal;
class Test
{
public:
Test()
{
s1 = signal.connect(bind(&Test::hello, this, _1));
s2 = signal.connect(bind(&Test::hello1, this, _1));
}
~Test()
{
printf("~Test()\n");
}
void hello(int n)
{
printf("Test::hello\n");
}
void hello1(int n)
{
printf("Test::hello1\n");
}
private:
Slot s1;
Slot s2;
};
int main()
{
shared_ptr<Test> p(make_shared<Test>());
p.reset();
signal.call(4);
testSignalSlotZero();
testSignalSlotOne();
testSignalSlotLife();
getchar();
return 0;
}