wqking / eventpp

Event Dispatcher and callback list for C++

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Problems with object slicing

aneksteind opened this issue · comments

I roughly have the following setup with names changed:

// a.h

enum class UpdateType { MeasurementUpdate, HealthUpdate };

// wrapper for listener with argument adapter
template <typename Params>
  eventpp::EventQueue<UpdateType, void(const Update&)>::Handle
  RegisterEventListener(const UpdateType& event_type,
                        std::function<Params>& callback) {
    return unified_event_queue_.appendListener(
        event_type, eventpp::argumentAdapter<Params>(callback));
  }

class Update {
  public:
    Update() {
    }

    virtual ~Update() {
    }
};

class Status : public Update {
 public:
  explicit Status(const A a, const B b, const C c)
      : a {a},
        b {b},
        c {c} {}

  A GetA() const {
    return a;
  }

  B GetB() const {
    return b;
  }

  C GetC() const {
    return c;
  }
 private:
  A a;
  B b;
  C c;
}

eventpp::EventQueue<UpdateType, void(const Update&)> unified_event_queue_;

I'm enqueueing with

// a.cc
A a {/* data I know about */};
B b {/* data I know about */};
C c {/* data I know about */};
unified_event_queue_.enqueue(
        UpdateType::MeasurementUpdate,
        Status(a, b, c));

and i've registered listeners with

// b.cc in a method of a class
std::function<void(const Status&)> status_f {
        [this](const auto& e) {
          this->CheckABC(e);
        }};
RegisterEventListener(UpdateType::MeasurementUpdate,
                                   status_f);

void CheckABC(const Status& status) {
  const auto a {status.GetA()};
  const auto b {status.GetB()};
  ...
}

when I check the attributes of status, I think that status has been sliced because the data I knew about is now no longer there when I call GetA() etc. My question is, where might this be happening? I've tried not to accidentally use anything but a reference, and I imagine that a dynamic cast is going on under the hood. I'm using unified_event_queue_.process() to dispatch. Would prefer not to use a pointer if I don't have to

In the document, it says,
"
If an argument is a reference to a base class and a derived object is passed in, only the base object will be stored and the derived object is lost. Usually shared pointer should be used in such situation.
"

The EventQueue only stores Update and the listener sees Update instead of Status.
You should use shared pointer.
eventpp::EventQueue<UpdateType, void(std::shared_ptr<Update>)>

Ah, this is what I was hoping I wouldn't have to do. I have this all working with shared pointers currently but was trying to move away from them for other reasons. Thank you for helping me here, though, with what was presented in this tutorial I thought I might be able to do it. Thank you anyway

how are you for example able to getKey in that tutorial and not have the same issues I'm encountering?

The argumentAdapter tutorial in your reference, works because it uses EventDispatcher. EventDispatcher passes the arguments directly to the listener without storing them in memory.
I will add notes on EventQueue may not work in that document to avoid misleading.

Ah okay that clears it up, thank you! Maybe I don't need to queue and can dispatch directly. Is dispatch blocking on the callbacks that get invoked with it?

Yes, dispatch in both EventDispatcher and EventQueue are called synchronized and blocked on the callbacks.

Thank you once again, I enjoy the library