Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Passing by reference in custom event

This thread is locked; no one can reply to it. rss feed Print
Passing by reference in custom event
Shpinxis
Member #16,080
September 2015

So, I am trying to have spawned (using "new") items set to NULL after the player picks them up. I am using custom events to relay that the player has picked up the item and after I want to delete the object. Using "delete this" didn't work, so I figured I would pass by reference the object to the player to have it set it to NULL after picking it up. I can't seem to figure how to pass the object by reference over the custom event though. Thanks.

//emit the event source that the food collided with the player
m_AlEvent.user.type = CUSTOM_EVENT_ID(FOODPICKUP_EVENT);
m_AlEvent.user.data1 = (intptr_t)this; <<<---"this" is the item
al_emit_user_event(&m_FoodPickupEventSource, &m_AlEvent, NULL);

Peter Hull
Member #1,136
March 2001

delete this is valid C++ - when you say 'didn't work', what happened?

Is the problem that you're holding a reference to a deleted object?

Pete

bamccaig
Member #7,536
July 2006
avatar

You won't be able to "pass by reference" through a pointer type. By definition, you have to pass by pointer. A reference in C++ is just compile-time syntactic sugar over a pointer. I think we're going to need a better explanation of what you're trying and why it's not working. As a side note, have you considered smart pointers?

Elias
Member #358
May 2000

bamccaig said:

As a side note, have you considered smart pointers?

A smart pointer will be hard to use in an ALLEGRO_EVENT which is a plain C struct without any copy-constructor rules - it gets duplicated to each event queue but bypasses any C++ magic. So in this very special case I'd say just use the reference counting and destructor callback provided by al_emit_user_event.

--
"Either help out or stop whining" - Evert

bamccaig
Member #7,536
July 2006
avatar

Shpinxis
Member #16,080
September 2015

The only way to pass a pointer through a custom event is using an "intptr_t" so I was wondering how to do it with that. Yes, when I said it didn't work its because something will still be holding the reference to the object and since delete doesn't set to NULL I have no way of knowing that it should not be accessed.

I'm trying to figure out a way to have a the object created dynamically in game at some point and then become independent. This can't truly happen in Allegro because you need something that is calling its draw function and its functions dealing with events, so a object will have its reference and be checking it. So I was going to try having the created object destroyed by whatever object receives its emitted event. I need to pass a reference to it though to do this so that when I set it to NULL the reference in the script that dropped the item will know too.

Elias
Member #358
May 2000

Something like this should work:

void delete_callback(ALLEGRO_USER_EVENT *event) {
    Type *self = static_cast<Type *>(event.data1);
    delete self;
}

al_emit_user_event(&m_FoodPickupEventSource, &m_AlEvent, delete_callback);

And where you receive the event:

if (event.type == CUSTOM_EVENT_ID(FOODPICKUP_EVENT)) {
    // handle the event
    al_unref_user_event(&event);
}

I suppose a smart pointer actually would work as well. You would still have to cast it to intptr_t and back, and the C code would make copies of it - but the al_emit_user_event reference counting would make sure only one of those copies is actually passed to the callback.

--
"Either help out or stop whining" - Evert

Shpinxis
Member #16,080
September 2015

That code doesn't seem to compile unless I'm doing something wrong.

void FoodPickup::delete_callback(ALLEGRO_USER_EVENT *event)
{
FoodPickup *self = static_cast<FoodPickup*>(event.data1);
delete self;
}

al_emit_user_event(&m_FoodPickupEventSource, &m_AlEvent, delete_callback);

The "(event.data1)" part as an error on "event" and the "al_emit_user_event" as an error on the "delete_callback" argument. Thanks.

bamccaig
Member #7,536
July 2006
avatar

event above is a pointer so I'm guessing you probably wanted event->data1, but perhaps you're also missing a header include or something?

The method is probably non-static so it has an implicit signature more like (Type * this, ALLEGRO_USER_EVENT * event). Normally you'd need an object instance to invoke that properly. My guess is that's what the compiler is complaining about.

It might work if you explicitly mark the method as static, which basically is like a global function that is just namespaced by the class. You may or may not have to qualify it with the type name: Type::method.

The main thing is you need to make sure that you don't store references to that object anywhere else. If you do need references elsewhere then you'll need to abstract the interface more so that you can signal that elsewhere to forget about the object too. That sounds to me like you don't actually want Allegro to clean up after itself with that data, but perhaps you'd still like to use Allegro's API to flag the object somehow (i.e., obj->alive = false) for later.

Or perhaps you can get away with smart pointers as I originally suggested if C is never going to access the data at all. You would pass a pointer to a smart pointer, not to the object, and then destroying the smart pointer would handle other instances of the underlying object properly... :-/ But that's kind of silly in a way mixing smart pointers with manual memory management. Append: Of course, then you'd have to allocate the smart pointer with new so that it doesn't destruct when leaving the scope of its origin, and I'm not sure if there are rules about not doing that... I recall smart pointers being particular.

Go to: