Reputation: 3960
In this webpage about Curiously Recurring Template Patten, the derived class can be instantiated on the stack (the Object Counter example, in which the base class template has a protected destructor): CRTP-wiki.. i compiled myself.
template <typename T>
struct counter
{
static int objects_created;
static int objects_alive;
counter()
{
++objects_created;
++objects_alive;
}
counter(const counter&)
{
++objects_created;
++objects_alive;
}
protected:
~counter() // objects should never be removed through pointers of this type
{
--objects_alive;
}
};
template <typename T> int counter<T>::objects_created( 0 );
template <typename T> int counter<T>::objects_alive( 0 );
class X : counter<X>
{
// ...
};
class Y : counter<Y>
{
// ...
};
But this answer says making the base class's destructor protected will prohibit instantiating derived class on stack: answer:
As answered already, Poco::RefCountedObject has protected destructor, so all classes inheriting from it can not be created on the stack....
So,
(1) is the this answer wrong? Or did I misunderstood?
(2) Why does the CRTP example make the destructor protected? Is it meant to prohibit instantiating a specialization of the base class template on stack? Can I instantiate a specialization of the base class template on heap (I tried, I can't, but don't know why)?
Thanks in advance!
Upvotes: 0
Views: 262
Reputation: 2146
I've created an example and objects on both stack and heap can be created. I think the answer is wrong and protecting the destructor has exactly meaning given in comment in your snippet: "objects should never be removed through pointers of this type". Also, 'protected' could be skipped if destructor were made virtual (since delete would always call inherited destructor first). I hope I didn't miss something here.
#include <cstdio>
template <typename T>
struct counter
{
static int objects_created;
static int objects_alive;
counter()
{
++objects_created;
++objects_alive;
}
counter(const counter&)
{
++objects_created;
++objects_alive;
}
protected:
~counter() // objects should never be removed through pointers of this type
{
--objects_alive;
}
};
template <typename T> int counter<T>::objects_created(0);
template <typename T> int counter<T>::objects_alive(0);
class X : counter<X>
{
public:
X()
{
printf("Hello from X %dth instance, %d still up\n", objects_created, objects_alive);
}
~X()
{
printf("Bye X\n");
}
};
int main()
{
{
X x; // hello x1
{
X x2; // hello x2
} // bye x2
X* x3 = new X(); // hello x3
X* x4 = new X(); // hello x4
delete x3; // bye x3
counter<X>* x5 = (counter<X>*)x4;
delete x5; // destructor is inaccesible, does not compile
}
return 0;
}
Upvotes: 1