patterncppMinor
Static Multilevel Inheritance with CRTP (Fast Intrusive Pointers)
Viewed 0 times
fastwithintrusiveinheritancecrtppointersmultilevelstatic
Problem
I wanted to have a way to be able to
which should call the destructor of the
Here we expose the CRTP pattern.
Let's do a quick example how that would work:
Deriving from this class, let's say:
and using a smart pointer (here an intrusion pointer), e.g.
(if you are interested, the code is below, for smart pointers I refere to
Question for multiple inheritance using CRTP:
The question came up, what to do, if let's say we want to derive a
Using now an intrusive pointer naively like
which will then only call the destructor of A obviously.
One idea would to correct this behavior would be: We need a way to inject the proper derived type into
How to do this?
My answer can be found here: CRTP Multiple Inheritance.
I just give my implemented answer to the problem and try to explain it:
The
static_cast to the proper derived type pointer of a base class to simulate a virtual call. Here the virtual call is for a reference counting base class:template class ReferenceCountingwhich should call the destructor of the
TDerived type if the reference count drops to zero. This class achieves this by static_casting to its derived class:delete static_cast(this)Here we expose the CRTP pattern.
Let's do a quick example how that would work:
Deriving from this class, let's say:
class A : public ReferenceCounting{ ...code of A... }and using a smart pointer (here an intrusion pointer), e.g.
IntrusionPtr p( new A() ) lets the object be reference counted properly.(if you are interested, the code is below, for smart pointers I refere to
boost::shared_ptr and boost::intrusive_ptr)Question for multiple inheritance using CRTP:
The question came up, what to do, if let's say we want to derive a
class B from A and would like to use it also with an intrusive pointer, of course we would like that because class A inherits already from ReferenceCounting:class B: public A { ...code... };Using now an intrusive pointer naively like
IntrusivePtr p(new B()) will TOTALY fail. Why? Because the class ReferenceCounting is instantiated with TDerived=Awhich will then only call the destructor of A obviously.
One idea would to correct this behavior would be: We need a way to inject the proper derived type into
ReferenceCounting (here that would be TDerived=B).How to do this?
My answer can be found here: CRTP Multiple Inheritance.
I just give my implemented answer to the problem and try to explain it:
template
class A : public ReferenceCounting >::type
>The
Select type trait injects the correct Derived type into ReferenceCounting, i.e A if PossibleDerived=void and PossibleDerived in any other Solution
I have some causes for concern regarding this pattern.
For example:
Forgetting to inject the CRTP parameter into a class that requires it will not give a compile error. It may not even give a run-time error. In this example it will just silently give you a memory leak that is a royal pain in the rear end to debug.
This will happily compile and give you a memory leak, even if C inherits properly from B with the CRTP parameters passed around:
This basically prevents use of
You may remember all the ins and outs of using this class every time but your next colleague may not even think about it and just go:
Cool, an intrusive pointer, I'll use it for this polymorphic code I'm writing.
Why do you not want to use a virtual destructor? This would make all your headaches go away. Yes you need a v-table, yes it's an extra indirection to figure out the correct destructor to call. But unless this is in the 1% of code that is your inner-most time critical loop, it will rarely matter on PC platforms.
For example:
class C : public B {
int* ptr;
}Forgetting to inject the CRTP parameter into a class that requires it will not give a compile error. It may not even give a run-time error. In this example it will just silently give you a memory leak that is a royal pain in the rear end to debug.
This will happily compile and give you a memory leak, even if C inherits properly from B with the CRTP parameters passed around:
IntrusivePtr a(new B());
IntrusivePtr b(new C());
a = b;This basically prevents use of
IntrusivePtr with polymorphic classes. But the compiler will happily accept such use and produce code that crashes at best or silently produces erroneous results/leaks memory at worst.You may remember all the ins and outs of using this class every time but your next colleague may not even think about it and just go:
Cool, an intrusive pointer, I'll use it for this polymorphic code I'm writing.
Why do you not want to use a virtual destructor? This would make all your headaches go away. Yes you need a v-table, yes it's an extra indirection to figure out the correct destructor to call. But unless this is in the 1% of code that is your inner-most time critical loop, it will rarely matter on PC platforms.
Code Snippets
class C : public B {
int* ptr;
}IntrusivePtr<B> a(new B());
IntrusivePtr<B> b(new C());
a = b;Context
StackExchange Code Review Q#54328, answer score: 3
Revisions (0)
No revisions yet.