c++ std::bind keeping object alive

Go To StackoverFlow.com

2

Here is the code, it's pretty straightforward.

class Foo
{
public:
    void print()
    {
        std::cout<<"Foo::print\n";
    }
}; 


Game::Game()
{
    {
        Foo foo;
        player.onclick = bind(&Foo::print,foo);

    }
    player.onclick();
}

After the inner scope is done the foo object goes out of scope, but the print method is still called, I guess this happens because player holds a reference to the foo object? Is there a way to stop this from happening? I don't want objects to stay alive and receive events when they are supposed to be destroyed.

Thanks.

2012-04-04 19:54
by Barış Uşaklı
that code is not straightforward. where is the rest - BЈовић 2012-04-04 19:55
What else do you need? bind is the std::tr1::bind. onclick is a simple function like this

std::functionBarış Uşaklı 2012-04-04 19:58

so you use tr1::bind. In that case, I need includes, main, et - BЈовић 2012-04-04 20:24


4

You are binding to a copy of foo; that copy lasts as long as the bound function object, while the original foo is destroyed at the end of its scope.

If you don't want to keep it alive, then bind to a pointer (&foo) or a reference (std::ref(foo)); and then you must be careful not to call the function object once foo has gone out of scope. Note that there's no way to tell from the function object that this has happened; calling it will give undefined behaviour.

In order to safely disconnect the object when it's destroyed, you would have to either arrange for its destructor to reassign onclick, or make some other object responsible for first reassigning onclick, and then destroying the object.

2012-04-04 19:59
by Mike Seymour
Ok, so I changed the bind to this : Foo foo; player.onclick = bind(&Foo::print,&foo);

And the print method is still getting called, wasn't what I was expecting - Barış Uşaklı 2012-04-04 20:01

@BlackKnight: Yes, the function object will still be callable, but calling it after foo is destroyed will give undefined behaviour (In this case, that behaviour is likely to print the message, since the member function doesn't do anything with the dead object). If you need the function object to be safely invalidated, then you'll need to do that yourself somehow - Mike Seymour 2012-04-04 20:03
Only way I can see handling that is making a Foo destructor and setting a zombie flag, and then returning from the handlers immediately if the object is dead. Is there a way to break the binding between player.onclick and Foo.print - Barış Uşaklı 2012-04-04 20:07
@BlackKnight : If the object is destroyed, checking a zombie flag won't help -- you're still in UB-land - ildjarn 2012-04-04 20:12
@BlackKnight: The only way to break the binding is to reassign onclick. The zombie flag won't work, since it will be destroyed along with the object. If you really want automatic invalidation, then you'll have to find a way to reassign onclick from the object's destructor. A better solution might be to make some other object responsible for both destroying the object and disconnecting it from whatever it's been connected to - Mike Seymour 2012-04-04 20:13
@BlackKnight, you can actually create some sort of smart pointer, that will be wrapped around actual Foo class, and in destructor of Foo, you can say to this container to set "zombie flag - Lol4t0 2012-04-04 20:17
The following seems to work : ` class Foo { public: Foo(Player& player):player(player) { player.onclick = bind(&Foo::print,this); } ~Foo() { player.onclick = NULL; }

void print() { std::cout<<"Foo::print\n"; } private: Player& player; };

Game::Game() {

{ Foo foo(player);

if(player.onclick) player.onclick();

}

if(player.onclick) player.onclick();

} - Barış Uşaklı 2012-04-04 20:34

@BlackKnight, the problem is that you can bind now only against onclik signal of player-class object. If this restriction is ok, this solution should wor - Lol4t0 2012-04-04 20:49


0

From your description it sounds like you actually want an event loop. While std::bind is useful for something like that it isn't one all by itself. I suggest you have a look at boost.signals

2012-04-04 20:03
by pmr


0

I think you should use shared_ptr when you assign Foo to Player, and keep a weak_ptr to Foo in Player. Then try to lock the weak_ptr in the onclick function to see if Foo is still alive. Something like this:

using namespace std;
class Foo
{
    public:
        void print()
        {
            cout<<"Foo::print\n";
        }
}; 

class Player
{
    public:
        weak_ptr<function<void()>> _onClickFuntion;
        void onclick()
        {
            shared_ptr<function<void()>> tempFunction(_onClickFunction.lock());
            if (tempFunction)
                tempFunction();
        }
}

Game::Game()
{
    {
        Foo foo;
        player._onClickFuntion = shared_ptr<function<void()>>(new bind(&Foo::print,foo));
    }
    player.onclick();
}
2012-05-11 13:45
by Albert Arnedo
Ads