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

时间:2016-09-22 21:13:22

标签: c++ c++11 memory-management stl allocator

上下文

我正在尝试创建一个自定义分配器,它在某些方面模仿std::allocator (非衍生自),但允许实例化分配器。我的通用容器具有构造函数,允许用户指定自定义Allocator对象的指针。如果未指定allocator,我希望它默认为从抽象NewDeleteAllocator类派生的单Allocator。这简单地包含了全局newdelete运算符。这个想法来自Pablo Halpern的Towards a Better Allocator Model

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

// '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 )如何知道{{1}的数据大小指向?这是安全的操作吗?根据我的理解,根据C ++标准,通过void指针删除可能会导致未定义的行为。如果这很糟糕,我还能怎样实现这个呢?

更多详情:

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

ptr

我使用Xcode的分析工具观察了程序的总内存使用情况。内存使用率保持不变为低值。我知道这不是检查内存泄漏的正确方法。我不知道编译器是否可以优化它。我只是试验这个想法。在对图书馆的架构做出任何承诺之前,我真的很感激主要问题的一些输入。整个方法可能首先存在缺陷。

感谢您的投入。我不想做出任何错误的假设。

1 个答案:

答案 0 :(得分:1)

对从::delete的调用返回的指针调用::new是安全的。 通过调用::delete[]返回的指针调用::new[]是安全的。 如果您不打算使用x类型,则通过拨打delete x时返回的指针调用auto x = new {...}是安全的。 如果您不打算使用x类型,则通过拨打delete[] x时返回的指针调用auto x = new {...}[z]是安全的。 混合是UB

  

&#34;但是:: delete(ptr)如何知道ptr所在数据的大小   指向&#34;

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