c ++ operator new [] / delete [] (不是我的)调用operator new / delete吗?
在我用自己的实现替换operator new
和operator delete
后,以下代码将调用它们:
int *array = new int[3];
delete[] array;
当我同时替换operator new[]
和operator delete[]
时,上面的代码只会调用 。
我的运营商实施:
void *operator new(std::size_t blockSize) {
std::cout << "allocate bytes: " << blockSize << std::endl;
return malloc(blockSize);
}
void *operator new[](std::size_t blockSize) {
std::cout << "[] allocate: " << blockSize << std::endl;
return malloc(blockSize);
}
void operator delete(void *block) throw() {
int *blockSize = static_cast<int *>(block);
blockSize = blockSize - sizeof(int);
std::cout << "deallocate bytes: " << *blockSize << std::endl;
free(block);
}
void operator delete[](void *block) throw() {
int *blockSize = static_cast<int *>(block);
blockSize = blockSize - sizeof(int);
std::cout << "[] deallocate bytes: " << *blockSize << std::endl;
free(block);
}
我还有第二个问题可能没那么相关,为什么代码打印出来:
[] allocate: 12
[] deallocate bytes: 0
而不是:
[] allocate: 16
[] deallocate bytes: 16
答案 0 :(得分:2)
由于分配运算符new
和new[]
几乎都做同样的事情(a),因此根据另一个来定义一个是有意义的。它们都用于分配给定大小的块,无论您打算使用它。同样适用于delete
和delete[]
。
事实上,标准是必需。 C ++ 11 18.6.1.2 /4
(例如)声明operator new[]
的默认行为是返回operator new(size)
。 /13
operator delete[]
对void *operator new(std::size_t sz) { return malloc(sz); }
void operator delete(void *mem) throw() { free(mem); }
void *operator new[](std::size_t sz) { return operator new(sz); }
void operator delete[](void *mem) throw() { return operator delete(mem); }
有类似的限制。
所以示例默认实现类似于:
new
当您替换delete
和new[]
个功能时,delete[]
和new[]
功能仍然会使用它们。但是,将delete[]
和new
替换为您自己的不调用delete
和int[3]
的函数会导致它们断开连接。
这就是为什么你会看到问题第一部分所描述的行为。
根据问题的第二部分,您会看到我期望看到的内容。 12
的分配要求三个整数,每个大小四个字节(在您的环境中)。这显然是0xa55a
个字节。
为什么它似乎释放零字节有点复杂。您似乎认为紧接在您给出的地址之前的四个字节是块的大小,但不一定如此。
实现可以自由地在内存领域中存储他们喜欢的任何控制信息(b),包括以下可能性(这绝不是详尽无遗的):
#include <iostream>
#include <memory>
// Need to check this is enough to maintain alignment.
namespace { const int buffSz = 16; }
// New will allocate more than needed, store size, return adjusted address.
void *operator new(std::size_t blockSize) {
std::cout << "Allocating size " << blockSize << '\n';
auto mem = static_cast<std::size_t*>(std::malloc(blockSize + buffSz));
*mem = blockSize;
return reinterpret_cast<char*>(mem) + buffSz;
}
// Delete will unadjust address, use that stored size and free.
void operator delete(void *block) throw() {
auto mem = reinterpret_cast<std::size_t*>(static_cast<char*>(block) - buffSz);
std::cout << "Deallocating size " << *mem << '\n';
std::free(mem);
}
// Leave new[] and delete[] alone, they'll use our functions above.
// Test harness.
int main() {
int *x = new int;
*x = 7;
int *y = new int[3];
y[0] = y[1] = y[2] = 42;
std::cout << *x << ' ' << y[1] << '\n';
delete[] y;
delete x;
}
或控制块的校验和)以捕捉竞技场损坏。除非你知道并控制内存分配函数如何使用它们的控制块,否则你不应该做出假设。首先,为了确保正确对齐,可以用其他无用的数据填充控制块。如果您想保存/使用所需的大小,您需要自己完成以下操作:
Allocating size 4
Allocating size 12
7 42
Deallocating size 12
Deallocating size 4
运行该代码会导致打印成功的值:
new MyClass
(a)在构造对象时,new MyClass[7]
和NULL
之间的差异以后比分配阶段。基本上,它们都会分配所需的内存一次,然后根据需要在该内存中构造尽可能多的对象(前者一次,后者七次)。
(b)并且允许实现不将任何控件信息内联存储。我记得在嵌入式系统上工作,我们知道没有任何分配超过1K。所以我们基本上创建了一个没有内联控制块的竞技场。相反,它有一点内存,几百个这样的1K块,并使用位图来决定哪些是正在使用的,哪些是免费的。
如果有人要求更多而不是1K,那么得到{{1}}。那些要求小于或等于1K的人无论如何得到1K。不用说,它比实现提供的通用分配功能快得多。