HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Callback system for events in a window

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
eventssystemcallbackforwindow

Problem

I have written a simple window event capture wrapper that gets events that happen to the window, and can be checked anywhere in the program through a global class. I wanted to be able to create a callback anywhere in the program with any event that I have asked to be checked. To hold the data that is returned from the events, I have used a pointer that is allocated whenever an event occurs, so I can grab the data returned later on in the program.

I don't want to use templates to hold the data since that would require a lot of objects to be created, or a lot of vectors for each specific event that I want. I find this to be too clunky, and I wanted a clean, simple solution.

Data that is captured

struct windowEventData
    {
        void *data = nullptr;
        std::string id;
        sf::Event::EventType event;

        bool polled = false;
    };


Window Event Manager

class windowEventManager
    {
        private:
            std::vector _subscribedEvents;

        public:
            void subscribe(const std::string &id, sf::Event::EventType event);
            void pollEvent(sf::Event event);
            void clearEvents();

            template
            T* hasEventPolled(const std::string &id);

            ~windowEventManager();
    };


Grabbing and setting the pointer

```
void windowEventManager::pollEvent(sf::Event event)
{
for (auto &eventCheck : _subscribedEvents)
{
if (eventCheck.event == event.type)
{
switch (event.type)
{
case sf::Event::KeyPressed:
case sf::Event::KeyReleased:
eventCheck.data = new sf::Event::KeyEvent(event.key);
break;
case sf::Event::MouseButtonPressed:
case sf::Event::MouseButtonReleased:

Solution

delete eventCheck.data;


This line invokes undefined behavior, because you aren't allowed to call delete on an incomplete type (and certainly not on void). Both GCC and Clang warn on this line:

(clang++)
prog.cc:4:5: warning: cannot delete expression with pointer-to-'void' type 'void *' [-Wdelete-incomplete]
    delete p;
    ^      ~

(g++)
prog.cc:4:12: warning: deleting 'void*' is undefined
     delete p;
            ^


Anyway, it won't do what you want (whatever that might be).

For an open set of types, the type-safe way to do what you're trying to do is to use type erasure, as seen in library containers such as std::function. (Shameless plug for my CppCon 2014 talk — type erasure is covered starting at 23m00s.) This kind of type-erasure is easy to implement yourself from scratch in about 20 lines of code.

For a closed set of types, you might see whether your compiler of choice supports C++17 std::variant and/or Boost boost::variant; you can use the visit function to perform an operation on a variant in a type-safe way, and of course you wouldn't even need delete at that point because you wouldn't be using pointers, just plain old value semantics. If you can't use Boost, then I don't recommend trying to implement variant yourself.

Code Snippets

delete eventCheck.data;
(clang++)
prog.cc:4:5: warning: cannot delete expression with pointer-to-'void' type 'void *' [-Wdelete-incomplete]
    delete p;
    ^      ~

(g++)
prog.cc:4:12: warning: deleting 'void*' is undefined
     delete p;
            ^

Context

StackExchange Code Review Q#144515, answer score: 3

Revisions (0)

No revisions yet.