【问题标题】:Can we allocate any number of byte we want in c++ ? (allocate 6 bytes for example for a type)我们可以在 c++ 中分配我们想要的任意数量的字节吗? (例如为一个类型分配 6 个字节)
【发布时间】:2021-11-07 13:16:50
【问题描述】:

我正在尝试编写一个国际象棋程序,在大多数情况下我只需要 4、6 或 8 个(这里我可以使用 char)字节。 那么我可以创建一个使用 4 个字节的类型,或者每个案例使用 4 个字节的数组吗?这将显着提高内存(以及效率?)。

谢谢大家。

【问题讨论】:

  • “我只需要 4、6 或 8 个(在这里我可以使用 char)字节” - char 是一个字节,所以你可以用它来做任何事情在这里列出。你的意思是字节还是位?
  • “这会显着增加内存” 我假设您正在尝试实现 AI 并存储状态。对于现代 PC 来说,使用 32 块中的每块多几个字节绝对是微不足道的,因此存储需要更多字节的单个状态应该不是问题。至于分配任意数量的字节:只要数字不为零,这绝对没有问题,除了实际上您将有效地消耗 8 个或更多字节。
  • 您是否会通过改善内存消耗获得好处取决于许多因素:如果有足够的主内存可用,优化缓存数据可能会产生更好的结果,但这可能正是与内存消耗相同。顺便说一句:如果可能存在过多的小内存分配问题,您可以通过为属于不同实体的数据分配和使用数组的一部分来解决这个问题......
  • 一般来说,对于这种情况,您应该简单地使用数据成员按大小递减顺序排列的结构,通常可以得到最小对齐的最小数据。例如struct small { unsigned short a; unsigned short b; unsigned char c; unsigned char d; }; 可能是 6 或 8 个字节并且非常有效。如果需要更多压缩,则更多的是逐案分析,而不是一些一般规则。
  • 您当前的数据定义在哪里?在提出问题时,您几乎应该总是提供一些代码来显示您所做的事情。

标签: c++ performance c++11 memory dynamic-memory-allocation


【解决方案1】:

如果你愿意,你可以分配一个大缓冲区并自己管理内存。

如果您这样做,请确保不要使用结构,或者如果您这样做,请了解“字节填充”或“字节对齐”,因为它会使每个结构占用比它“需要”更多的空间。

一旦您分配了原始内存(例如,使用 malloc、std::vector 或使用数组),您需要“紧密存储”您的数据。

这里有一些代码:

char array[5000] = { 0 }; // or char* array = malloc(5000);
// Let's say you want to store several "char, int" structs

const int structSize = sizeof(char) + sizeof(int);

*(char*)&array[0 * structSize] = 'a';
*(int*)&array[0 * structSize + sizeof(char)] = 1;

*(char*)&array[1 * structSize] = 'b';
*(int*)&array[1 * structSize + sizeof(char)] = 2;

*(char*)&array[2 * structSize] = 'c';
*(int*)&array[2 * structSize + sizeof(char)] = 3;

警告:在上面的代码中,如果您存储的是结构/类而不是原始类型(char、int...),请确保在内存位置上使用“placement new”。

如果您使用“struct { char, int }”,则其大小将为 8 个字节(在大多数计算机上,并非全部),其中 3 个是填充(未使用的内存)。

请注意,当您增加内存使用量时,您会降低 cpu 效率(这就是填充的意义所在)。

或者,请参阅this article 以了解告诉编译器不要进行填充的替代方法(使用“#pragma pack”)。

#pragma pack(1)
struct nopadding
{
    char first;
    int second;
};

sizeof(nopadding); // <- is now equal to 5 instead of 8

【讨论】:

  • 在 C++ 中 operator new 通常是分配内存。 valgrind 也可能是一个有用的工具。使用最近调用的GCC 编译代码为g++ -Wall -Wextra -O -g
  • 使用mallocemplacement new 而不是只使用std::vector&lt;My6ByteStruct&gt; foo(400) 有什么好处?这是一个 6 字节结构的 400 个实例,具有自动构造、销毁和内存管理功能。
  • 未对齐的内存访问不可移植。如果一个人不关心可移植性,那么它可能无论如何都可以使用特定的属性、编译指示或编译器标志来从其struct 中获得所需的对齐。我不会从一般问题中推荐任何破解(没有任何代码)。
  • 即使忽略未对齐的访问,未能为这些数字调用placement-new 会导致未定义的行为,即使它可能在实践中起作用。 (从 C++20 开始,您可以改用 std::launder。)
  • @ZeroZ30o Placement-new 对他们来说确实是一个空操作,但标准仍然需要它,请参阅 [basic.life]this cppreference article
猜你喜欢
  • 2018-01-22
  • 2016-05-02
  • 1970-01-01
  • 2018-06-27
  • 2013-08-26
  • 1970-01-01
  • 1970-01-01
  • 2012-08-27
  • 2012-12-28
相关资源
最近更新 更多