I have a method that takes a parameter that is a reference to the base class, and I call the method body calls, completing the method implementation in queue<function<void()>>
The problem is that I was hoping to lock the method parameter by value so that each lambda in the queue could execute its own copy.
But if I commit by value, then the lambda copy of the reference parameter seems to cut it off, leaving me with a copy of the base class instead of the actual derived class in the link.
If I take the parameter by reference instead, I get the actual derived class in lambda, but obj may go out of scope between method calls or its state may change.
Remember that a method must be reentrant, but not asynchronous or parallel.
This is an example of what I mean (omitting the queue):
struct BaseObj { virtual ~BaseObj() = default; }; struct DerivedObj : public BaseObj { }; void someMethod(BaseObj& obj) { // obj is of type BaseObj: std::cout << "\nobj type:" << typeid(obj).name(); auto refLambda = [&] { // captured obj is of type DerivedObj: std::cout << "\nrefLambda::obj type:" << typeid(obj).name(); }; auto valLambda = [=] { // captured obj is of type BaseObj: // presumably because it was copied by value, which sliced it. std::cout << "\nvalLambda::obj type:" << typeid(obj).name(); }; refLambda(); valLambda(); }
The output when calling the method is as follows:
DerivedObj obj{}; someMethod(obj);
There is:
obj type:10DerivedObj refLambda::obj type:10DerivedObj valLambda::obj type:7BaseObj
Currently, the only way I was able to save the derived type in method calls is:
- passing the selected heap of the object from the calling code.
- capture by reference in lambda.
- make sure you do not change the source code in the calling code.
- finally removing a bunch of obj after the method returns.
Like this:
DerivedObj* obj = new DerivedObj(); someMethod(*obj); delete obj;
But I was hoping I could just pass the link from the stack of the calling code and it would be fine even if something happened inside someMethod that caused another call to someMethod .
Any ideas?
One of the approaches that I was thinking about, but I'm not sure how to do it, inside `someMethod ', moving the parameter to the heap, executing the lambda and then finally deleting it (since the caller doesn't actually use it after calling this method). But not sure if this is really hacked (I just thought about it because it is a bit like what Objective-C blocks do).
update:
This is the solution I have so far:
void Object::broadcast(Event& event) { auto frozenEvent = event.heapClone(); auto dispatchBlock = [=]() { for (auto receiver : receivers) { receiver.take(event); } delete frozenEvent; _private->eventQueue.pop(); if (!_private->eventQueue.empty()) { _private->eventQueue.front()(); } }; _private->eventQueue.push(dispatchBlock); if (_private->eventQueue.size() == 1) { _private->eventQueue.front()(); } }
Yes, I know, I use raw pointers ... (eeeeevil ....: p), but at least I can save the method signature with the ref parameter.
The clone method is located line by line:
template <class T> struct ConcreteEvent : public Event { virtual Event* heapClone() { return new T(*(T*)this); }