2

I was thinking about a design for custom handles. The thought is to prevent clients from copying around large objects. Now a regular handle class would probably suffice for that, but it doesn't solve the "dangling reference problem";

If a client has multiple handles of the same object and deletes the object via one of them, all the others would be invalid, but not know it, so the client could write or read parts of the memory he shouldn't have access to.

Is there a design pattern to prevent this from happening?


Two ideas:

  1. An observer-like pattern where the destructor of an object would notify all handles.

  2. "Handle handles" (does such a thing even exist?). All the handles don't really point to the object, but to another handle. When the object gets destroyed, this "master-handle" invalidates itself and therefore all that point to it.

  • 2
    Sure there is. For instance, C++ has spent the last decades doing little else but add features that would allow people with sufficient skills to implement such things. Google "smart pointer" for just one example, and prepare to spend a long time reading up on them. – Kilian Foth Jun 5 '14 at 15:14
  • easy way to avoid the problem is by collecting all deletes to same place in the code, thus deletions happen in large groups. ownership of the object need not be in the handle... – tp1 Jun 5 '14 at 15:19
  • @KilianFoth I do know of smart pointers (so I won't spend too much time reading up on them), but was interested in implementing a self-made alternative to disable clients from storing shared_ptrs to an object that should've long been destroyed. Maybe I'm overdoing it, but I want to rule out as many possible usage errors as possible. – iFreilicht Jun 6 '14 at 0:04
  • @iFreilicht: If you want to be able to destroy the object and detect destruction just before usage then use std::weak_ptr. This is just the other side of std::shared_ptr. – Martin York Jun 10 '14 at 3:53
  • I do use them, but I've decided to wrap them so they fit my needs perfectly. A nice side effect is even better encapsulation and the freedom to change the implementation at will. – iFreilicht Jun 10 '14 at 12:12
6

C++11 introduced two new utility classes: std::shared_ptr and std::unique_ptr. If you need to control a resource through multiple handles, then wrap it in a std::shared_ptr, which is a reference-counted smart pointer that cleans up the resource when there are no more pointers to it. std::unique_ptr is designed for single ownership, but it too will automatically clean up the resource it holds when the handle itself is destroyed.

While the name _ptr seems to imply pointers, both classes can be customized to work with any kind of resource that needs to be manually given back to the OS. Here's a hypothetical example that uses FILE* handles from C (why you would use this instead of streams is up to you...)

struct FILE_deleter {
    void operator() (FILE* fp) const {
        fclose(fp);
    }
};

void f()
{
    std::shared_ptr<FILE> sp(fopen("some-file.txt"), FILE_deleter{});

    // Now do whatever you want with sp: make copies of it, pass it around, whatever.
}
  • Instead of making a functor for fclose, you can just pass fclose directly to the shared_ptr constructor. :) – Jon Purdy Jun 5 '14 at 18:36
  • Yes, that is true. – bstamour Jun 5 '14 at 19:43
  • I am actually using shared_ptr as of now, but it didn't seem to fit my purpose perfectly. I should probably rethink where to return weak_ptr. Still a good answer. :) – iFreilicht Jun 5 '14 at 23:56
  • For users other than C++11 there is also an implementation outside from boost. Also mentionable in special situations is the boost::intrusive_ptr which is quite fast. – Sven Oct 29 '14 at 17:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.