0

I'm trying to figure out a way that I can send messages to other objects in C++. For example when an object collides with another object, it will send out a message that there was a collision that occured. I'm trying to use boost:signal's, but they don't seem to be exactly what I want, unless I'm just using them in the wrong manner.

Here's the main reason:

I don't really understand is why this code still works even known that the object I allocated on the stack has been destroyed...

class SomeClass
{
public:

   void doSomething()
   {
      std::cout << "Testing\n";
   }
};


int main(int argc, char** argv)
{
     boost::signal<void ()> sig;


     {
           SomeClass obj;
           sig.connect(std::bind(&SomeClass::doSomething, &obj));
     }

     sig();
}

Okay so that code outputs:

Testing

Why does it still work? Shouldn't I get some sort of run-time error or it not call the method at all? I don't really want that to actually happen, I want the connection to be lost as soon as the object is destroyed.

I was thinking of sending messages another way, perhaps Objective-C style using their type of delegates, where you would inherit from a class to have a message sent to you. But then again, it seems to lead to me for some confusion, such as if I want multiple delegates I would have an array of delegate pointers, and if a delegate gets destroyed I would have to remove it from that array... Which could cause some confusion.

e.g.

class ColliderDelegate
{
public:

    virtual ~ColliderDelegate() {}

    virtual void onCollisionEnter(Collider* sender, Collider* withWho) = 0;
    virtual void onCollisionExit(Collider* sender, Collider* withWho) = 0;
    virtual void onCollisionStay(Collider* sender, Collider* withWho) = 0;

private:

    // I would have to have an array of Collider's that this object is connected to,
    // so it can detatch itself when it's destroyed...
 };

 class Collider
 {
 public:
    void add(ColliderDelegate* delegate);
    void remove(ColliderDelegate* delegate);


    void checkForCollisionWith(Collider*);

 private:

     // I would have to have an array of ColliderDelegate's that this object
     // needs to send information to.
 };

Can anyone suggest how I could implement what I want to do? I'm really confused on what I should do...

4

3 回答 3

2

The signal slot in your example is a non-virtual member function, which doesn't access any object members. Non-virtual function address is resolved in compile-time, this pointer is not needed here -- so there's no reason for crash.

On the other hand, you could use singal "tracking" feature to disconnect the slot automatically. See the following: tracking in Boost.Signals; tracking in Boost.Signal2.

于 2012-07-15T12:04:50.907 回答
1

Why does it still work?

It's actually Undefined Behavior because doSomething() is being called on a destructed object. (To see this, add a print statement to the destructor.) When you ran the program, "Testing" was printed to the screen, but the program could have crashed.

What you might consider is adding a connection member to SomeClass. This way, in the SomeClass destructor you could disconnect the signal–slot connection.

于 2012-07-15T12:04:31.787 回答
0

To answer at least some of your questions:

Why does it still work? Shouldn't I get some sort of run-time error or it not call the method at all?

I guess you are just lucky. You object gets destroyed nevertheless you can still call methods on it. It is undefined behaviour but in your case it does not crash.

You are not very specific on what problem you want to solve. So it is difficult to tell what is the best solution.
For your delegate approach take a look at std::shared_ptr and std::weak_ptr. You can hold arrays of std::weak_ptr and call your delegates through those.

Or maybe boost::signal is the right choice. Have a look at scoped connections.

于 2012-07-15T12:04:18.757 回答