根据这个问题的答案:“How does delete[] "know" the size of the operand array?”
您的分配器将跟踪您分配的内存量
和
如何自由知道释放多少内存“
是的,内存块大小由malloc存储在“某处”(通常在块本身中),这就是免费知道的。但是,new [] / delete []是一个不同的故事。后者基本上在malloc / free之上工作。 new []还存储它在内存块中创建的元素数量(独立于malloc),以便后来delete []可以检索并使用该数字来调用适当数量的析构函数
这是否意味着delete []独立于指针指向的位置?以下代码是否有效或是否会导致内存泄漏?
void createArray(){
char* someArray = new char[20];
readData(someArray);
//Is this delete still valid after moving the pointer one position?
delete[] someArray;
}
char readData(char* &arr){
char value = *arr;
//Let it point to the next element
arr += 1;
return value;
}
答案 0 :(得分:8)
是的。如果您更改new[]
-ed指针值,然后在其上调用delete[]
运算符,则表示您正在调用未定义的行为:
char* someArray = new char[20];
someArray++;
delete[] someArray; // undefined behavior
而是将原始值存储在不同的指针中,并在其上调用delete[]
:
char* someArray = new char[20];
char* originalPointer = someArray;
someArray++; // changes the value but the originalPointer value remains the same
delete[] originalPointer; // OK
答案 1 :(得分:1)
您可能有兴趣知道新的和删除真正做了什么(获得一些许可,忽略异常和对齐):
template<class Thing>
Thing* new_array_of_things(std::size_t N)
{
std::size_t size = (sizeof(Thing) * N) + sizeof(std::size_t);
void* p = std::malloc(size);
auto store_p = reinterpret_cast<std::size_t*>(p);
*store_p = N;
auto first = reinterpret_cast<Thing*>(store_p + 1);
auto last = first + N;
for (auto i = first ; i != last; ++i)
{
new (i) Thing ();
}
return first;
}
template<class T>
void delete_array_of_things(Thing* first)
{
if (first)
{
auto store_p = reinterpret_cast<std::size_t*>(first) - 1;
auto N = *store_p;
while (N--)
{
(first + N)->~Thing();
}
std::free(store_p);
}
}
要点:
您指定的指针不是指向已分配内存开头的指针。数组的大小存储在为对象数组提供存储的内存之前(掩盖一些细节)。
delete[]
理解这一点,并希望您提供new[]
返回的指针。
答案 2 :(得分:0)
一般规则是您只能删除从new
获得的指针。在非数组版本中,您可以将指针传递给使用new
创建的基类子对象(授予基类具有虚拟析构函数)。对于数组版本,它必须是相同的指针。
对于第二个(数组)形式,expression必须是空指针值或先前由new-expression的数组形式获得的指针值。如果expression是其他任何东西,包括它是否是由new-expression的非数组形式获得的指针,则行为是未定义的。