::operator delete( void * ) 是否知道用 ::operator new( size_t ) 分配的内存大小
Does ::operator delete( void * ) know the size of memory allocated with ::operator new( size_t )
上下文:
我正在尝试创建一个自定义分配器,它在某些方面模仿 std::allocator
(不是派生自),但允许实例化分配器。我的通用容器具有构造函数,允许用户指定指向自定义 Allocator
对象的指针。当没有指定分配器时,我希望它默认为从抽象 Allocator
class 派生的单例 NewDeleteAllocator
。这只是简单地包装了全局 new
和 delete
运算符。这个想法来自 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 )
如何知道 [=25] 的数据大小=] 指的是什么?这是一个安全的操作吗?根据我的理解,根据 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
"but how does ::delete( ptr ) know the size of the data that ptr is
pointing to"
C++中的动态分配内存通常是通过堆来实现的。堆最初分配了非常大量的 space,然后他处理它,让程序处理它的随机块。堆存储它分配的每个内存块的大小。例如,如果你需要 8 个字节的内存,堆至少为你保留 12 个字节,前 4 个字节保存大小,后 8 个字节保存数据。比,它returns一个指向8字节的指针。所以,在删除的过程中,程序通过访问指针知道了多少"to delete" - 4.
上下文:
我正在尝试创建一个自定义分配器,它在某些方面模仿 std::allocator
(不是派生自),但允许实例化分配器。我的通用容器具有构造函数,允许用户指定指向自定义 Allocator
对象的指针。当没有指定分配器时,我希望它默认为从抽象 Allocator
class 派生的单例 NewDeleteAllocator
。这只是简单地包装了全局 new
和 delete
运算符。这个想法来自 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 )
如何知道 [=25] 的数据大小=] 指的是什么?这是一个安全的操作吗?根据我的理解,根据 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
"but how does ::delete( ptr ) know the size of the data that ptr is pointing to"
C++中的动态分配内存通常是通过堆来实现的。堆最初分配了非常大量的 space,然后他处理它,让程序处理它的随机块。堆存储它分配的每个内存块的大小。例如,如果你需要 8 个字节的内存,堆至少为你保留 12 个字节,前 4 个字节保存大小,后 8 个字节保存数据。比,它returns一个指向8字节的指针。所以,在删除的过程中,程序通过访问指针知道了多少"to delete" - 4.