Fixing sigslot copy constructors.

They used to work, but were broken by a somewhat recent refactoring of
sigslot.h.

It's reasonable for signals and slots to have copy constructors, since
a class that uses signals/slots may want to be copyable.

BUG=webrtc:7342

Review-Url: https://codereview.webrtc.org/2842423002
Cr-Commit-Position: refs/heads/master@{#17942}
This commit is contained in:
deadbeef 2017-04-29 00:27:04 -07:00 committed by Commit bot
parent 12a467ffca
commit 8b1d862bfe
2 changed files with 44 additions and 10 deletions

View File

@ -407,15 +407,12 @@ namespace sigslot {
_signal_base& operator= (_signal_base const& that);
public:
_signal_base(const _signal_base& s) : _signal_base_interface(&_signal_base::do_slot_disconnect, &_signal_base::do_slot_duplicate) {
_signal_base(const _signal_base& o) : _signal_base_interface(&_signal_base::do_slot_disconnect, &_signal_base::do_slot_duplicate) {
lock_block<mt_policy> lock(this);
connections_list::const_iterator it = m_connected_slots.begin();
connections_list::const_iterator itEnd = m_connected_slots.end();
while(it != itEnd)
for (const auto& connection : o.m_connected_slots)
{
it->getdest()->signal_connect(this);
m_connected_slots.push_back(*it);
++it;
connection.getdest()->signal_connect(this);
m_connected_slots.push_back(connection);
}
}
@ -528,13 +525,21 @@ namespace sigslot {
{
}
has_slots(has_slots const& o) : has_slots_interface(&has_slots::do_signal_connect, &has_slots::do_signal_disconnect, &has_slots::do_disconnect_all)
{
lock_block<mt_policy> lock(this);
for (auto* sender : o.m_senders) {
sender->slot_duplicate(&o, this);
m_senders.insert(sender);
}
}
~has_slots()
{
this->disconnect_all();
}
private:
has_slots(has_slots const&);
has_slots& operator= (has_slots const&);
static void do_signal_connect(has_slots_interface* p, _signal_base_interface* sender)

View File

@ -36,6 +36,10 @@ class SigslotReceiver : public sigslot::has_slots<slot_policy> {
~SigslotReceiver() {
}
// Provide copy constructor so that tests can exercise the has_slots copy
// constructor.
SigslotReceiver(const SigslotReceiver&) = default;
void Connect(sigslot::signal0<signal_policy>* signal) {
if (!signal) return;
Disconnect();
@ -222,7 +226,7 @@ TEST_F(SigslotMTLockTest, LockSanity) {
}
// Destroy signal and slot in different orders.
TEST(DestructionOrder, SignalFirst) {
TEST(SigslotDestructionOrder, SignalFirst) {
sigslot::signal0<>* signal = new sigslot::signal0<>;
SigslotReceiver<>* receiver = new SigslotReceiver<>();
receiver->Connect(signal);
@ -232,7 +236,7 @@ TEST(DestructionOrder, SignalFirst) {
delete receiver;
}
TEST(DestructionOrder, SlotFirst) {
TEST(SigslotDestructionOrder, SlotFirst) {
sigslot::signal0<>* signal = new sigslot::signal0<>;
SigslotReceiver<>* receiver = new SigslotReceiver<>();
receiver->Connect(signal);
@ -243,3 +247,28 @@ TEST(DestructionOrder, SlotFirst) {
(*signal)();
delete signal;
}
// Test that if a signal is copied, its slot connections are copied as well.
TEST(SigslotTest, CopyConnectedSignal) {
sigslot::signal<> signal;
SigslotReceiver<> receiver;
receiver.Connect(&signal);
// Fire the copied signal, expecting the receiver to be notified.
sigslot::signal<> copied_signal(signal);
copied_signal();
EXPECT_EQ(1, receiver.signal_count());
}
// Test that if a slot is copied, its signal connections are copied as well.
TEST(SigslotTest, CopyConnectedSlot) {
sigslot::signal<> signal;
SigslotReceiver<> receiver;
receiver.Connect(&signal);
// Fire the signal after copying the receiver, expecting the copied receiver
// to be notified.
SigslotReceiver<> copied_receiver(receiver);
signal();
EXPECT_EQ(1, copied_receiver.signal_count());
}