C++ C++;11内存池类-从void*进行静态_转换的解决方法?

C++ C++;11内存池类-从void*进行静态_转换的解决方法?,c++,c++11,C++,C++11,我想要一个类p,它有一个静态delete\u all成员函数,该函数将删除p类型或从p派生的类型的所有动态分配的实例 以下是我所拥有的: #include <unordered_set> using namespace std; struct P { static unordered_set<P*> pool; static void* operator new(size_t size) { void* p = ::operat

我想要一个类
p
,它有一个静态
delete\u all
成员函数,该函数将删除
p
类型或从
p
派生的类型的所有动态分配的实例

以下是我所拥有的:

#include <unordered_set>
using namespace std;

struct P
{
    static unordered_set<P*> pool;

    static void* operator new(size_t size)
    {
        void* p = ::operator new(size);
        pool.insert(static_cast<P*>(p));
        return p;
    }

    static void operator delete(void* p)
    {
        pool.erase(static_cast<P*>(p));
        ::operator delete(p);
    }

    static void delete_all()
    {
        while (!pool.empty())
            delete *(pool.begin());
    }

    virtual ~P() {}; // polymorphic
};

unordered_set<P*> P::pool;
我关心的部分是静态地将
void*
指针转换为
p*
。我有一种感觉,在某些情况下,这将导致未定义的行为,例如,在派生类上调用new时,P基类子对象不从派生类的开头开始。内存块还不知道它是派生类的类型,因此来自void的
static\u cast
不会给出P子对象的正确位置

这是个问题,我说得对吗?我怎样才能修好它


另外,
p
是否还有一个我不知道的问题?

您的静态类型转换是一个问题,这是正确的,原因与您描述的完全相同


除非我遗漏了一些明显的东西,否则您不需要整个操作员new/operator delete舞蹈。只要让P的构造函数在池中存储此,然后P的析构函数将其从池中删除即可。这样,您总是能够处理诚实的P*指针。确保在所有构造函数中都这样做(回想一下,如果您没有明确提供或禁用构造函数,编译器将生成复制和移动构造函数)。

我见过的一种技术涉及跟踪
操作符new
中新增的
内容,当我们有一个有效的指针时,在构造函数中执行池:该指针将位于
void*
void*+size\t
之间。但是,您的
new
是否会在
new-Derived
中调用?您也可以使用
动态转换(ptr)
构造。这将确保您获得正确的指针,或者在强制转换失败时返回NULL。但是,这不是免费的,因为此转换是在运行时完成的。@Yakk:“但是,您的新代码会在新派生中调用吗?”我不明白您在问什么。是的,由
新派生的
生成的动态分配对象应添加到池中,如果尚未添加,则由
删除所有
删除。@Xaqq:我认为这不起作用,因为
返回的内存块::operator new(字节)
中还没有必要的类型信息来支持
dynamic\u cast
@Xaqq:不,您不能
dynamic\u cast
将类型为
void*
的表达式转换为任何指针类型。参见5.2.7.2他有一个显式定义的析构函数,因此不会生成移动构造函数。
struct D : P
{
    ...
};

int main()
{
    D d1;
    D* d2 = new D();
    D* d3 = new D();

    delete d2;

    P::delete_all(); // deletes d3, but not d1 or d2
}