:operator delete(void*)是否知道使用::operator new(size_t)分配的内存大小

Does ::operator delete( void * ) know the size of memory allocated with ::operator new( size_t )

本文关键字:operator 分配 内存 size void delete 是否 new      更新时间:2023-10-16

上下文:

我正在尝试创建一个自定义分配器,它在某些方面模仿std::allocator(不是从(,但允许实例化分配器。我的通用容器有构造函数,允许用户指定指向自定义Allocator对象的指针。当没有指定分配器时,我希望它默认为从抽象Allocator类派生的单例NewDeleteAllocator。这简单地封装了全局newdelete运算符。这个想法取自Pablo Halpern的《走向更好的分配器模型》。

使用自定义分配器的客户端代码:

// 'foo_container.hpp'
// enclosed in package namespace
template <class T>
class FooContainer
{
private:
    // -- Private member properties --
    Allocator * allocator;
public:
    // -- Constructors --
    FooContainer( Allocator * allocator = 0 )
    {
        this->allocator = !allocator ? (Allocator *)defaultAllocator : allocator;
    }
    FooContainer( const FooContainer &rhs, Allocator * allocator = 0 )
    {
        // don't implicitly copy allocator
        this->allocator = !allocator ? (Allocator *)defaultAllocator : allocator;
        // copying logic goes here
    }
}

自定义分配器实现:

// 'allocator.hpp'
// enclosed in package namespace
class Allocator
{
public:
    virtual ~Allocator(){ };
    virtual void * allocate( size_t bytes ) = 0;
    virtual void deallocate( void * ptr ) = 0;
};
class NewDeleteAllocator : public Allocator
{
public:
    virtual ~NewDeleteAllocator()
    {
    }
    virtual void * allocate( size_t bytes )
    {
        return ::operator new( bytes );
    }
    virtual void deallocate( void * ptr )
    {
        ::operator delete( ptr );    // memory leak?
    }
private:
};
//! @todo Only for testing purposes
const Allocator * defaultAllocator = new NewDeleteAllocator();

主要问题:

我知道通过new进行分配也可能将有关分配的信息与指针一起存储。我意识到用作用域解析运算符::调用delete与仅调用delete并不完全相同,但::delete( ptr )如何知道ptr所指向的数据的大小?这是一个安全的操作吗?根据C++标准,根据我的理解,通过void指针进行删除可能会导致未定义的行为。如果这很糟糕,我还能怎么实现呢?

更多详细信息:

我用以下代码做了一些非常粗略的初步测试:

// inside member function of 'FooContainer'
for( size_t i = 0; i < 1000000; i++ )
{
    for( size_t j; j = 1; j < 20; j++ )
    {
        void * ptr = allocator->allocate( j );
        allocator->deallocate( ptr );
    }
}

我用Xcode的评测工具观察了程序的总内存使用情况。内存使用率保持恒定在较低的值。我知道这不是检查内存泄漏的正确方法。我不知道编译器是否能对此进行优化。我只是在试验这个想法。在我对我的图书馆的架构做出任何承诺之前,我真的很感谢对主要问题的一些意见。整个方法可能一开始就有缺陷。

感谢您的投入。我不想做任何糟糕的假设。

在调用::new返回的指针上调用::delete是安全的。对从对::new[]的调用返回的指针调用::delete[]是安全的。如果不丢弃x的类型,那么在从对auto x = new {...}的调用返回的指针上调用delete x是安全的。如果不丢弃x的类型,那么在从对auto x = new {...}[z]的调用返回的指针上调用delete[] x是安全的。混合是UB

"但是::delete(ptr(如何知道ptr的数据大小指向">

C++中动态分配的内存通常是通过堆来实现的。堆最初分配了很大的空间,然后他处理它,让程序处理其中的随机块。堆存储它分配的每个内存块的大小。例如,如果您需要8个字节的内存,堆至少为您保留12个字节,将大小保留在前4个字节中,将数据保留在后8个字节中。然后,它返回一个指向8个字节的指针。因此,在删除过程中,程序通过访问指针-4知道要删除多少。