C++ “全球”;“安置”;删除[]
我正在尝试用自己的分配器替换new/delete。所以,覆盖放置新的和删除-非常高兴。看起来像这样C++ “全球”;“安置”;删除[],c++,visual-c++,C++,Visual C++,我正在尝试用自己的分配器替换new/delete。所以,覆盖放置新的和删除-非常高兴。看起来像这样 void* operator new( size_t size, Allocator* a ) { return a->Alloc( size ); } template<class T> inline void MyDelete( T* p, Allocator* a ) { if( p ) { p->~T();
void* operator new( size_t size, Allocator* a )
{
return a->Alloc( size );
}
template<class T> inline void MyDelete( T* p, Allocator* a )
{
if( p )
{
p->~T();
a->Free( p );
}
}
这里,如果存在~MyClass(),则pA的值为buf+4,分配的内存量为sizeof(MyClass)*5+4。但是,如果没有dtor,则pA==buf,分配的内存量为sizeof(MyClass)*5
所以我的问题是——这种行为是一种语言标准,并且在编译器之间是一致的,还是MSVC特有的?还有其他人能很好地解决这个问题吗?我想唯一的选择是不使用new[],而是自己进行构造,这很好,但是调用代码语法有点不寻常。。或者强制每个类都有析构函数。您可以在分配器中查找指针,从簿记中找出大小,并使用sizeof T计算元素数。如果有疑问,请咨询专家: 但是我们以后如何才能正确地删除这些对象呢?之所以没有内置的“placement delete”来匹配新的placement,是因为没有通用的方法来确保正确使用它。C++类型系统中的任何东西都不允许我们推断P1点到ALANE A1中分配的对象。可以将指向分配到任意位置的任何X的指针分配给p1
该链接的其余部分将继续介绍如何纠正这种情况。没有“位置删除”这样的术语。正如您所说,如果您使用placement new分配了一些内容,那么在解除分配时,您需要手动调用析构函数,然后还要处理为placement new分配的实际内存缓冲区 但是,如果不手动跟踪您自己的分配大小,您尝试执行的操作是不可能的。原因是“placement new”的整个要点是将分配与对象初始化解耦。因此,在placement new中,分配内存缓冲区的行为与构建或销毁任何对象可能(或可能不)生活在该缓冲区中的行为是完全独立的
这样,例如,如果分配了一些缓冲区,比如<代码> char Buf(1000)< /C>,然后使用Puffy new构建缓冲区中的
void operator delete(void*p)
或void operator delete[](void*p)
时插入代码以展开簿记
如果您确实使用新签名覆盖new,编译器希望您在new期间出现异常时使用匹配的签名定义delete-这是唯一一次使用它
在不可调用的意义上,没有位置删除,但它是在异常情况下定义的(不执行任何操作)
长答案:
本主题提出了一些有趣的观点:
void*操作符new[](size\t sz,Allocator*a)
重载到底是什么void操作符delete[](void*p,Allocator*a)
,以使编译器插入其簿记终结void*运算符new[](size_t sz,Allocator*a)
声明了(非放置)new的重载。它永远不会为新的位置插入簿记代码,因为新位置的关键是你自己处理它
第2点:R.E.“没有像placement delete这样的东西”,你会在例如VS2k8新标题中发现一些看起来非常像它的东西(并被如此评论)。它只是一个存根,用于在放置新文件时发生异常的情况。然而,看起来确实不能以有意义的方式调用placement delete
第三点:如果有办法,我找不到。这是问题的核心
就实际解决问题而言,这似乎是一场失败
例如:
//intention: user provides memory pool, compiler works out how many bytes required
//and does its own book-keeping, as it would for a void* operator new[](size_t sz) overload
//calling syntax: CObj* pMyArr = new(pMyMemPool) CObj[20];
void* operator new[](size_t sz, IAlloc* pMemPool)
{ return pMemPool->alloc(sz); }
//problem: don't know the syntax to call this!
//e.g. delete[](pMyMemPool) pMyArr is syntax error
void* operator delete[](void* p, IAlloc* pMemPool)
{ return pMemPool->free(p); }
//nb: can be called as operator delete(pMyArr, pMyMemPool);
//but compiler does not finish its book-keeping or call dtors for you in that case.
请注意,非数组new和delete也存在这种不对称性。然而,由于(根据经验)所讨论的编译器没有额外的簿记,所以可以使所有这些都正常工作。再说一次,我不知道这是否体现在标准中
void* operator new(size_t sz, IAlloc* pMemPool)
{ return pMemPool->alloc(sz); }
//don't know syntax to get this called by compiler!
void operator delete(void* p, IAlloc* pMemPool)
{ pMemPool->free(p); }
//is ok though, can work around
template<class T> void tdelete(void* p, IAlloc* pMemPool)
{
//no problems, p points straight at object
p->~T();
operator delete(p, pMemPool);
//OR just
pMemPool->free(p);
}
void* operator new[](size_t sz, IAlloc* pMemPool)
{ return pMemPool->alloc(sz); }
//again, don't know syntax to end up here.
void operator delete[](void* p, IAlloc* pMemPool)
{ pMemPool->free(p); }
//can't work around this time!
template<class T> void tarrdelete(void* p, IAlloc* pMemPool)
{
//problem 1: how many to dtor?
for(int i=0; i<???; ++i)
{ reinterpret_cast<T*>(p+i)->~T(); }
//problem 2: p points at first element in array. this is not always the address
//that was allocated originally.
pMemPool->free(?);
//as already explained by OP, no way to tell if p is address allocated or
//address allocated+4 bytes, or something else altogether. this means no way to know what address to un-alloc or how many dtors to call.
}
摘要:在启用编译器“魔法”的情况下,是否有语法允许使用扩展参数列表调用delete重载。或者,是否有方法通过替代向新放置添加参数
可疑答案:否
推论:您不能完全自由地偏离6个内置的新签名。这样做会导致new超负荷,编译器生成了簿记,但无法访问相应的delete以解除簿记
警告:您可以偏离内置签名,但只需注入代码,删除时无需再次处理(例如插入)。如果您无法使用分配的void*运算符new(size\t s)
版本,则delete仍将正常工作
(一些事实陈述来自调试器中的实验,可能只适用于MSVC8(cl9)。OP坐在我旁边的桌子上。)您不覆盖“位置删除”
void* operator new(size_t sz, IAlloc* pMemPool)
{ return pMemPool->alloc(sz); }
//don't know syntax to get this called by compiler!
void operator delete(void* p, IAlloc* pMemPool)
{ pMemPool->free(p); }
//is ok though, can work around
template<class T> void tdelete(void* p, IAlloc* pMemPool)
{
//no problems, p points straight at object
p->~T();
operator delete(p, pMemPool);
//OR just
pMemPool->free(p);
}
void* operator new[](size_t sz, IAlloc* pMemPool)
{ return pMemPool->alloc(sz); }
//again, don't know syntax to end up here.
void operator delete[](void* p, IAlloc* pMemPool)
{ pMemPool->free(p); }
//can't work around this time!
template<class T> void tarrdelete(void* p, IAlloc* pMemPool)
{
//problem 1: how many to dtor?
for(int i=0; i<???; ++i)
{ reinterpret_cast<T*>(p+i)->~T(); }
//problem 2: p points at first element in array. this is not always the address
//that was allocated originally.
pMemPool->free(?);
//as already explained by OP, no way to tell if p is address allocated or
//address allocated+4 bytes, or something else altogether. this means no way to know what address to un-alloc or how many dtors to call.
}
//sz may include extra for book-keeping
void* operator new[](size_t sz)
{ return GAlloc->alloc(sz); }
//works fine, compiler handled book-keeping and p is the pointer you allocated
void operator delete[](void* p)
{ return GAlloc->free(p); }