boost signal disconnect problem: slot can still be triggered after slot object has been destroyed

32 Views Asked by At

By far I've encountered the same problem. The document in boost web says that the disconnection occurs when 'An object tracked by the slot is destroyed.', however, I tested it doesn't work in that way. So I prefer to disconnect manually although it's little bit troublesome.

My test code :

class MySignal {
public:
    boost::signals2::signal<void ()> signal_one;
    boost::signals2::signal<void ()> signal_two;

};

class MySlot {
public:
    void SlotOne() {
        std::cout << "slot_one" << std::endl;
    }
    void SlotTwo() {
        std::cout << "slot_two" << std::endl;
    }
};

int main() {

    MySignal signal;
    auto* slot = new MySlot;

    auto c = connect(signal.signal_one, slot, &MySlot::SlotOne);
//    c.disconnect();

    if (slot != nullptr) {
        delete slot;
        slot = nullptr;
    }

    signal.signal_one();

    return 0;
}

Can anybody tell me why the slot can still be triggered while I already destroyed the slot object?

I can only convince myself that the boost's document says the 'disconnection' can occur under some circumstances but doesn't say it will happen automatically.

Words below are what the boost document says:
Signal/slot disconnections occur when any of these conditions occur:
1.The connection is explicitly disconnected via the connection's disconnect method directly, or indirectly via the signal's disconnect method, or scoped_connection's destructor.
2.An object tracked by the slot is destroyed.
3.The signal is destroyed.

1

There are 1 best solutions below

0
Alex Guteniev On

The document in boost web says that the disconnection occurs when 'An object tracked by the slot is destroyed.', however, I tested it doesn't work in that way. So I prefer to disconnect manually although it's little bit troublesome.

The key word here is "tracked". Tracking is made by making the slot object inheriting from trackable class:

class MySignal : public boost::signals2::trackable  {
public:
    boost::signals2::signal<void ()> signal_one;
    boost::signals2::signal<void ()> signal_two;
};

Here when you connect like this:

auto c = connect(signal.signal_one, slot, &MySlot::SlotOne);

the signal will have the pointer to slot to track.

Note that with lambda slot you'll have to pass the pointer as an additional parameter, see Using boost::signals2::trackable with lambdas

When you don't track an object lifetime, and call a slot of deleted object, like in your example, you have an Undefined Behavior. Which is still likely to manifest in executing your slot normally, since you don't reference this, and the slot function is nonvirtual.