c++ - 自定义分配器,包括放置新案例

标签 c++ memory-management new-operator allocation

我正在尝试为 C++ 实现一个自定义分配器,它适用于任何形式的 new/delete/malloc/free。

我的程序是如何工作的,我在程序开始时分配了一个x 字节的内存池并使用它们。例如,当有人写 int* a= new int; 时,我的程序将从可用的内存池中返回地址并将其标记为已分配,并且该地址连同分配的大小从内存池。当有人写delete a;时,地址返回到内存池中,可以再次使用。

我的问题是我不完全理解如何new(placement) 有效,我应该如何处理它,因为当我的函数被调用以在 new/malloc 上分配内存时,我只有程序需要的内存大小作为参数我只是返回一个可用地址到要使用的内存。考虑以下示例

auto p = (std::string*)malloc(5 * sizeof(std::string));
void * placement = p;
new(placement) std::string(4, (char)('a'));
std::cout<< *p;

在第一行,我的自定义分配将从我的内存池中向 p 返回一个地址,其中可用内存总数为 5* sizeof(std::string)),在第三行行我的自定义分配器将再次分配内存返回另一个地址。当我打印 *p 时,它打印的正是我所期望的 aaaa

它应该这样工作吗?

最佳答案

一个普通的 new 做两件事:

  • 分配存储;和

  • 构造一个对象。

现在我们要把这两个步骤分开。分配原始存储空间很容易,但是在 C++ 中没有在给定地址构造对象的“ native ”方法。因此,new 运算符被重载以实现此目的,通过返回第一步的给定指针。

我们不需要相应的delete,因为我们可以手动调用析构函数。在 C++17 中,std::destroy_at 被添加到标准库中。自 C++20 起,std::construct_at 可用于构造对象而不是放置 new:

std::construct_at(p, 4, 'a');

C++ Super-FAQ很好地解释了 placement new:

什么是“placement new”,我为什么要使用它?

There are many uses of placement new. The simplest use is to place an object at a particular location in memory. This is done by supplying the place as a pointer parameter to the new part of a new expression:

#include <new>        // Must #include this to use "placement new"
#include "Fred.h"     // Declaration of class Fred
void someCode()
{
  char memory[sizeof(Fred)];     // Line #1
  void* place = memory;          // Line #2
  Fred* f = new(place) Fred();   // Line #3 (see "DANGER" below)
  // The pointers f and place will be equal
  // ...
}

Line #1 creates an array of sizeof(Fred) bytes of memory, which is big enough to hold a Fred object. Line #2 creates a pointer place that points to the first byte of this memory (experienced C programmers will note that this step was unnecessary; it’s there only to make the code more obvious). Line #3 essentially just calls the constructor Fred::Fred(). The this pointer in the Fred constructor will be equal to place. The returned pointer f will therefore be equal to place.

ADVICE: Don’t use this “placement new” syntax unless you have to. Use it only when you really care that an object is placed at a particular location in memory. For example, when your hardware has a memory-mapped I/O timer device, and you want to place a Clock object at that memory location.

DANGER: You are taking sole responsibility that the pointer you pass to the “placement new” operator points to a region of memory that is big enough and is properly aligned for the object type that you’re creating. Neither the compiler nor the run-time system make any attempt to check whether you did this right. If your Fred class needs to be aligned on a 4 byte boundary but you supplied a location that isn’t properly aligned, you can have a serious disaster on your hands (if you don’t know what “alignment” means, please don’t use the placement new syntax). You have been warned.

You are also solely responsible for destructing the placed object. This is done by explicitly calling the destructor:

void someCode()
{
  char memory[sizeof(Fred)];
  void* p = memory;
  Fred* f = new(p) Fred();
  // ...
  f->~Fred();   // Explicitly call the destructor for the placed object
}

This is about the only time you ever explicitly call a destructor.

关于c++ - 自定义分配器,包括放置新案例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58900136/

相关文章:

c++ - 无法在新安装的 Visual Studio Code 上运行 C++ 代码

c++ - 如何在 C++ 中重新分配?

c++ - 如何阻止重载的 new() 从 C++/Linux 中的 Ostream 调用?

c++ - Ax=B 使用 boost 1_58 求解稀疏矩阵

c++ - 使用内联汇编程序从 GCC 中的共享库调用函数

c++ - OpenGL 相机类

c++ - 如何从成员函数中释放对象?

C - 一行代码正在更改结构的地址

iphone - 当稍后需要引用传递给类中函数的 NSString 时,正确的方法是什么? (iPhone 开发者)

java - 如何使用给定的构造函数创建对象