[SL operator delete
未返回的非空指针上调用SL operator new
被认为是未定义的行为,如此处针对(1)和(2)所述:https://en.cppreference.com/w/cpp/memory/new/operator_delete
除非ptr是空指针或是以前从
operator new(size_t)
或operator new(size_t, std::nothrow_t)
的标准库实现中获得的指针,否则此函数的标准库实现的行为是不确定的。
因此,混合使用operator new
,operator delete
和operator new[]
,operator delete[]
的行为也是不确定的行为。我在标准说明中找不到任何内容,说明这是否也适用于调用用户分配方法的替换operator new
和operator delete
。例如:
void* operator new(std::size_t p_size)
{
void *ptr = UserImplementedAlloc(p_size);
return ptr;
}
void* operator new[](std::size_t p_size)
{
void *ptr = UserImplementedAlloc(p_size);
return ptr;
}
void operator delete(void* p_ptr)
{
UserImplementedFree(p_ptr);
}
void operator delete[](void* p_ptr)
{
UserImplementedFree(p_ptr);
}
以下内容是否不确定?假设UserImplementedAlloc
总是返回正确的地址,而不是nullptr
。
struct Simple
{
explicit Simple(); //Allocates m_bytes
~Simple(); //Frees m_bytes
char * m_bytes;
};
/*Placement new is not replaced or overridden for these examples.*/
//Example A
{
//Allocates and invokes constructor
Simple* a = new Simple();
//Invokes destructor
a->~Simple();
//Deallocates
UserImplementedFree(static_cast<void*>(a));
}
//Example B
{
//Allocates
void* addr = UserImplementedAlloc(sizeof(Simple));
//Invokes constructor
Simple* b = new (addr) Simple();
//Invokes destructor and deallocates
delete b;
}
我不是在寻找关于这是否不好的方法的演讲,我只是在试图确定这是否是定义的行为。
即使分配和释放功能是用户定义的,使用delete
和new[]
或delete[]
和new
的确是UB。这样做的原因是,在分配数组时,编译器有时需要能够编写一个计数器,该计数器告诉它在看到delete[]
调用时要调用多少个析构函数。如果将new
与delete[]
配对,则后者可能会读取一些希望找到计数器的内存,并进行一些无意义的操作。如果将new[]
与delete
配对,则后者只能调用一个析构函数。
在C ++ 17中,引用为[expr.delete] / 2:
...在第一种选择(删除对象)中,
delete
的操作数的值可以是空指针值,即指向由先前的[[new-表达式,或指向表示该对象基类的子对象(4.5)的指针(第13条)。如果不是,则行为是不确定的。在第二种选择(删除数组)中,delete
的操作数的值可以是空指针值,也可以是由先前数组new-expression产生的指针值。如果不是,则行为是不确定的。 ...
首先手动调用析构函数,然后删除void *是不安全的。您不会在C ++语义中删除相同的指针。