【问题标题】:Does ::operator delete( void * ) know the size of memory allocated with ::operator new( size_t )::operator delete( void * ) 是否知道使用 ::operator new( size_t ) 分配的内存大小
【发布时间】:2017-01-31 14:49:15
【问题描述】:

上下文:

我正在尝试创建一个自定义分配器,它在某些方面模仿 std::allocator(不是派生自),但允许实例化分配器。我的通用容器有构造函数,允许用户指定一个指向自定义Allocator 对象的指针。当没有指定分配器时,我希望它默认为从抽象 Allocator 类派生的单例 NewDeleteAllocator。这只是包装了全局 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 ) 如何知道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 的分析工具观察了程序的总内存使用情况。内存使用量保持在一个较低的值。我知道这不是检查内存泄漏的正确方法。我不知道编译器是否可以优化它。我只是在试验这个想法。在我对我的图书馆的架构做出任何承诺之前,我非常感谢对主要问题的一些投入。首先,整个方法可能存在缺陷。

感谢您的意见。我不想做任何不好的假设。

【问题讨论】:

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


    【解决方案1】:

    在调用::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。

    【讨论】:

    • 有道理。谢谢。
    • 这是分配和解除分配的一种示例方法,并非所有分配器每次分配都有 4 字节的开销。
    • 我担心这可能取决于实现。想象一下,我在堆上分配了一个对象。然后将其指针转换为 void 指针。那不等于这个问题中的问题吗? stackoverflow.com/questions/12761875/…
    • “对从 new 调用返回的指针调用 delete 是安全的。”不清楚你在这里的意思。您可以对来自new 运算符表达式的指针使用delete 运算符,也可以对来自::operator new(size_t) 的指针调用::operator delete(ptr),但不能混合匹配。
    • @JacquesNel:如果一个类没有定义operator newoperator delete,那么在指向该类类型的指针上使用newdelete 运算符将导致类指向全局::operator new()::operator delete 函数。
    猜你喜欢
    • 2016-04-21
    • 1970-01-01
    • 2014-01-23
    • 2015-05-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-08
    • 2014-09-17
    • 2012-06-20
    相关资源
    最近更新 更多