受保护的析构函数禁止在堆栈上创建派生 class 的对象?

Protected destructor disables creating derived class's objects on stack?

在这个关于 Curiously Recurring Template Patten 的网页中,派生的 class 可以在堆栈上实例化(Object Counter 示例,其中基础 class 模板具有受保护的析构函数):CRTP-wiki..我自己编译的。

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>
{
    // ...
};

但是这个答案说保护基础 class 的析构函数将禁止在堆栈上实例化派生的 class::

As answered already, Poco::RefCountedObject has protected destructor, so all classes inheriting from it can not be created on the stack....

所以,

(1) 这个答案错了​​吗?还是我理解错了?

(2)为什么CRTP例子要保护析构函数?这是否意味着禁止在堆栈上实例化基础 class 模板的特化?我可以在堆上实例化基础 class 模板的特化吗(我试过了,我不能,但不知道为什么)?

提前致谢!

我已经创建了一个示例,可以创建堆栈和堆上的对象。 我认为答案是错误的,保护析构函数的含义在您的代码段的评论中给出:"objects should never be removed through pointers of this type"。此外,如果析构函数是虚拟的,则可以跳过 'protected'(因为 delete 总是首先调用继承的析构函数)。希望我没有遗漏任何东西。

#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;
}