23

Type erasure - is that how you call it?

How boost::shared_ptr stores its deleter and how boost::function stores its function object?

Is there any tutorial that teaches the trick?

What is the run-time cost of using type-erased function objects?

manlio
  • 18,345
  • 14
  • 76
  • 126
pic11
  • 14,267
  • 21
  • 83
  • 119
  • 2
    did you try to google before asking? there is plenty of informantion on the web. the old Thamas Becker article: http://www.artima.com/cppsource/type_erasure.html or this well known book: http://www.boostpro.com/mplbook/ and lots of other resources. – Gene Bushuyev Jun 12 '11 at 21:36
  • 18
    @GeneBushuyev: the entire purpose of SO is basically to make Google searches unnecessary. If you want to learn about some programming-related subject, you can Google it, and either (1) find a SO answer, or (2) get unreliable information which may or may not be correct and help you. Or you can (2) search/ask for it on SO, and get answers that are peer-reviewed, rated by quality, and virtually guaranteed to be useful. Please don't tell people to Google instead of asking questions here. It's counterproductive. – jalf Mar 04 '12 at 00:16

1 Answers1

28

The idea is simple, you define a base class that has an interface with the functionality you need, and then inherit from it. Since the type erased class uses only that interface, the actual type underneath is forgotten and erased. Alternatively, if the only needed interface can be expressed as free functions you can store pointers to the free functions.

namespace detail {
   struct deleter_base {
      virtual ~deleter_base() {}
      virtual void operator()( void* ) = 0;
   };
   template <typename T>
   struct deleter : deleter_base {
      virtual void operator()( void* p ) {
         delete static_cast<T*>(p);
      }
   };
}
template <typename T>
class simple_ptr {
   T* ptr;
   detail::deleter_base* deleter;
public:
   template <typename U>
   simple_ptr( U* p ) {
      ptr = p;
      deleter = new detail::deleter<U>();
   }
   ~simple_ptr() {
      (*deleter)( ptr );
      delete deleter;
   }
};

This is a really simplified smart pointer, but the idea is there. In the particular case of shared_ptr, the deleter is stored as part of the reference count object, that is held by pointer.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • shared_ptr deleter doesn't have to be derived from anything. – pic11 Jun 12 '11 at 21:28
  • 7
    @pic11: The deleter passed in to the `shared_ptr` does not need to inherit, *but* type erasure is implemented by using inheritance (or function pointers) internally. – David Rodríguez - dribeas Jun 12 '11 at 21:31
  • How you call a function object if you don't know its static type and/or it doesn't inherit from a base class? – pic11 Jun 12 '11 at 21:35
  • 1
    @pic11: [Here's a recent answer I gave that used type erasure](http://stackoverflow.com/questions/6122094/building-boostoptions-from-a-string-boostany-map/6123962#6123962), take a look so you can get an idea of what David is talking about, in code. – GManNickG Jun 12 '11 at 21:39
  • Shouldn't `deleter` derive from `deleter_base` in this example? At the moment it doesn't. – Sjoerd Jun 12 '11 at 21:42
  • @Sjoerd: Thanks, you are right, I missed the inheritance relationship (together with the namespace...). – David Rodríguez - dribeas Jun 12 '11 at 21:45
  • Thanks everyone. I need some time to digest the material. – pic11 Jun 12 '11 at 21:49
  • @David In the `simple_ptr` destructor you call `operator()`, but `deleter` is a pointer, so the line should read `(*deleter)(ptr);`. Maybe it would be better to have a normal member function instead of `operator()`. I usually call these one-purpose-type operations with a witty name like `doIt()`, `execute()` or `makeItHappen()` :-) – Fiktik Mar 03 '12 at 10:54
  • from first para of your answer : `the actual type underneath is forgotten and erased` <-- couldn't understand that, please explain in easy term? Thanks – Mr.Anubis Jul 26 '12 at 18:10
  • @Mr.Anubis: The type of the `shared_ptr`/`function` does not reflect the type of the `deleter`/functor that was used to create it. When you get a `shared_ptr` or `function` objects, the types used to create it are no longer available. – David Rodríguez - dribeas Jul 26 '12 at 18:42
  • @DavidRodríguez-dribeas I apologize for late reply. Can you please go little easy on me? . I understood the example i.e interfaces and virtual function does the magic under the hood and how thing are working but you words/sentences don't gets in to my mind e.g `the types used to create it are no longer available.` – Mr.Anubis Jul 30 '12 at 17:50
  • 2
    @Mr.Anubis: Maybe easier with an example: `void f( shared_ptr )`, and two shared pointers: `shared_ptr p( new int ); int i; shared_ptr q(&i, noop_deleter);` (assuming the appropriate deleter). The deleters do not take part in the type of the `shared_ptr`, which means that you can do both `f(p)` and `f(q)`. Compare that with `std::unique_ptr` where the deleter is a template argument: `void f( unique_ptr )`, and `unique_ptr q( &i )`, then `f(q)` is an error. The type of the deleter is part of the type of the smart pointer. – David Rodríguez - dribeas Jul 30 '12 at 17:54
  • ... in the first case, the type of the deleter is *erased* and the type of the smart pointer does not reflect it, in the second case, the type of the deleter is part of the type of the smart pointer. – David Rodríguez - dribeas Jul 30 '12 at 17:55
  • @DavidRodríguez-dribeas cool!!, that example made everything more clearer, thanks a lot for quick help and your patience :) – Mr.Anubis Jul 30 '12 at 17:59
  • This answer is good for illustration, but it actuality don't the semantics of `shared_ptr` require `p` to be captured in the deleter-capturing-helper-class, not supplied later? (perhaps `std::shared_ptr` and `boost::shared_ptr` differ in this regard) – Ben Voigt Sep 04 '14 at 00:59