gpt4 book ai didi

c++ - c++ operator new[]/delete[] 是否调用 operator new/delete?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:42:33 26 4
gpt4 key购买 nike

C++ operator new[]/delete[] (不是我的)是否调用 operator new/delete?

在我用自己的实现替换operator newoperator 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

最佳答案

由于分配运算符 newnew[] 几乎做同样的事情(a),所以有道理的是根据对方来定义。它们都用于分配给定大小的 block ,无论您打算将其用于什么。 deletedelete[] 同上。

事实上,这是标准要求的。 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); }

当您替换 newdelete 函数时,new[]delete[] 函数将仍然在幕后使用它们。但是,将 new[]delete[] 替换为您自己的调用您的 newdelete 导致它们断开连接。

这就是为什么您会看到问题第一部分中描述的行为。


根据您问题的第二部分,您看到的是我期望看到的。 int[3] 的分配要求三个整数,每个整数大小为四个字节(在您的环境中)。这显然是 12 字节。

为什么它似乎释放了零字节有点复杂。您似乎认为紧接在给定地址之前的四个字节是 block 的大小,但事实并非如此。

实现可以自由地将他们喜欢的任何控制信息存储在内存区域(b),包括以下可能性(这绝不是详尽无遗):

  • 当前内存分配的大小;
  • 指向下一个(也可能是上一个)控制 block 的链接;
  • 一个哨兵值(例如 0xa55a 或控制 block 的校验和)以捕获竞技场损坏。

除非您知道并控制内存分配函数如何使用它们的控制 block ,否则您不应该做出假设。首先,为了确保正确对齐,可以用其他无用的数据填充控制 block 。如果你想保存/使用请求的大小,你需要自己做类似的事情:

#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

(a) new MyClassnew MyClass[7] 之间的区别比分配阶段,当对象被构造时。基本上,它们都一次分配所需的内存,然后根据需要在该内存中构造尽可能多的对象(前者一次,后者七次)。


(b) 并且允许实现不存储内嵌任何控制信息。我记得在嵌入式系统上工作时,我们知道任何分配都不会超过 1K。所以我们基本上创建了一个没有内联控制 block 的竞技场。相反,它有一小块内存,其中有数百个 1K block ,并使用位图来决定哪些正在使用,哪些是空闲的。

如果有人要求 超过 1K,则得到 NULL。那些要求小于或等于 1K 的人无论如何都会得到 1K。不用说,它比实现中提供的通用分配函数快得多。

关于c++ - c++ operator new[]/delete[] 是否调用 operator new/delete?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48129890/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com