Search code examples
c++templateslambdavariadic-templates

Is there a way to detect if object instance is deleted (in lambda)?


I have this small template function to store my callback function for later "callback".

std::function<void(std::string)> stored_callback;

template<class ReadFileCallback, typename Object, class ...T>
void fileMgr_ReadWithCallback(std::string filename, ReadFileCallback callback, Object* object, T ...params) {
    std::cout << "fileMgr_ReadWithCallback is processing file: " << filename << std::endl;

    stored_callback= [=](std::string s) {
        (object->*callback)(s, params...);
    };
}

void calledLater() {
  stored_callback("somestring");
}

I'm using it from a class like this:

void MyClass::Read() {
  fileMgr_ReadWithCallback("myfile", &MyClass::ReadResult, this, fileId);
}

This works nicely, but I have a terrible fear that it can cause a real mess if object gets invalidated (goes out of scope).

As MyClass can be put onto heap:

MyClass* c=new MyClass();
c->Read(); // callback stored
delete c; // c invalidated
calledLater(); // ???

If I try running this, it does not cause any error. But if something overwrites c's former space, it would cause a terrible UB. Or I'm mistaken?

Is there any way when c is deleted for either of these:

  • not call the stored_callback, or
  • not call (object->*callback)(s, params...);

Is this good for storing a weak_ptr?

stored_callback = [=](std::string s) { 
  std::weak_ptr<Object> obj = object; //or std::make_shared?
  if (auto spt = obj.lock()) (spt->*callback)(s, params...);
};

Solution

  • Is there a way to detect if object instance is deleted

    Yes, so long as you manage its lifetime with shared_ptr, and optionally track it with weak_ptr when you don't want to extend that lifetime.

    There is no general way to do this for "unmanaged" objects, meaning those allocated and managed directly via raw pointers, or locals with automatic scope.

    You can't detect whether the object still exists via a raw pointer, because if it was deleted or went out of scope, dereferencing the pointer is illegal in the first place. So, you must either

    1. write your code to not destroy the object while the raw pointer exists (ie, static correctness)
    2. not use raw pointers and instead use a smart pointer (most likely shared_ptr and weak_ptr) to control the object's lifetime
    3. have the object somehow detach itself from callbacks when it is destroyed (which is intrusive, as now each object that could be used in a callback needs to know about it)