#include <stdlib.h>
#include <string>
#include <atomic>
struct base_C_event {
const char* ev;
const char* da;
};
template <class T>
struct ref_counter {
private:
std::atomic<std::ptrdiff_t> _counter;
};
struct derived_event : ref_counter<derived_event>, base_C_event {
derived_event() : event_type(), event_data() {
ev = event_type.c_str();
da = event_data.c_str();
}
std::string event_type;
std::string event_data;
};
struct derived_event2 : base_C_event, ref_counter<derived_event2> {
derived_event2() : event_type(), event_data() {
ev = event_type.c_str();
da = event_data.c_str();
}
std::string event_type;
std::string event_data;
};
struct some_cool_event {
int type;
void* payload;
};
void OnEvent(const some_cool_event* event) {
auto e = static_cast<base_C_event*>(event->payload); //...and then shows itself here
printf("%s - %s\n", e->ev, e->da);
}
int main() {
derived_event evt;
evt.event_type = "type";
evt.event_data = "Hello World";
derived_event2 evt2;
evt2.event_type = "hi";
evt2.event_data = "there";
some_cool_event my_event;
my_event.type = 1;
my_event.payload = &evt; //Problem starts here...
OnEvent(&my_event);
my_event.type = 2;
my_event.payload = &evt2;
OnEvent(&my_event);
return 0;
}
output: (compiled with g++)
(null) - type
type - Hello World
now, in my real environment (XCode) the ordering of inheritance for derived_event
causes a BADACCESS exception; with g++ it just produces (null) as shown in the output.
however, the ordering for derived_event2
works just fine.
The way i understand the standard, the order of multiple inheritance effects the order of constructors and destructors, and also the layout of the memory. Can anyone explain what is happening here?
EDIT:
I have actually figured this out. The line that sets the event object to the void* payload, and then the ensuing static_cast<> back to the base type... seems to invalidate the first pointer (ev
) because the struct becomes just a memory layout at that point, so the pointers are getting set to the first two pointer size chunks... in this case std::atomic<std::ptrdiff_t>
and then the base_C_event. so the cast is grabbing the data for the std::atomic and using that as the pointer address for ev
, and what was originally ev
in the derived object is now what da
points at.
I unfortunately in my real scenario can't use composition for the base_C_event
in my derived_event
and send that. that's why the refcounting is there, so i have to send the derived object so that later on in a callback i can decrement the refcount.
Is there a way to prevent this from happening?