0

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!

Leedehai
  • 3,660
  • 3
  • 21
  • 44
  • 2
    Don't link to code samples. Links die. Put the code in the question. And especially don't link to pages which contain a lot of code samples that are unrelated. Do you really expect everyone to *look* for what you want to ask about? – StoryTeller - Unslander Monica Aug 02 '17 at 07:50
  • @StoryTeller Thanks for pointing this out and I have added the code. But please ask nicely next time:) – Leedehai Aug 02 '17 at 07:56
  • 3
    Well, it's simple. The answer you linked is wrong either due to a mistake in writing or lack of knowledge. A protected destructor doesn't prevent creation of dervied objects. – StoryTeller - Unslander Monica Aug 02 '17 at 07:58

1 Answers1

1

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;
}
R2RT
  • 2,061
  • 15
  • 25