【问题标题】:Understanding memory access in C++ with placement new使用新位置了解 C++ 中的内存访问
【发布时间】:2016-10-09 20:25:18
【问题描述】:

目前正在学习 C++,我正在重新审视我们的教授部分编写的一个小型内存管理器作为练习,由于我太长时间忽视了我的 C++ 技能,我无法理解内存和放置 new 的实际工作原理.所以基本上我有多个 Bucket 对象,它们都包含一定数量的块,每个块都可以有一定数量的内存。 BucketAdmin 类拥有所有这些 Bucket 对象。

BucketAdmin::BucketAdmin(void)
{
m_baseMemory = reinterpret_cast<unsigned char *>(malloc(sizeof(Bucket) * NUM_OF_BUCKETS) );

Bucket* base_pointer = reinterpret_cast<Bucket*>(m_baseMemory);
std::cout << &base_pointer<< "     "  <<  &base_pointer + sizeof(Bucket) *     NUM_OF_BUCKETS  << "     " << sizeof(Bucket) * NUM_OF_BUCKETS << std::endl;

for (unsigned short i = 0; i < NUM_OF_BUCKETS; i++)
{
    m_buckets[i] = new (&base_pointer[i])Bucket(m_bucketSizes[i], BUCKET_CAPACITY/m_bucketSizes[i]);
}
}

所以这里的代码让我很困惑。 Bucket 的大小为 16 字节(如 sizeof(Bucket) 所述,桶数为 5。这意味着 m_baseMemory 分配 80 字节的 ram 并且是 char 指针(reinterpret_cast 如何准确工作以及为什么使用两次?). 接下来,通过将之前的内存地址转换为 Bucket 指针来创建存储桶指针 - 这是如何以及为什么会这样?当我输出两个地址时,它们彼此非常不同。我理解前两个的方式行是分配了80字节的内存,其地址保存在m_baseMemory中。然后,因为我们要构造Bucket对象,所以将该指针强制转换为Bucket指针,这样我们就可以遍历for中的Bucket-adresses-循环(基本上一个 i 是 i*sizeof(Bucket) 的偏移量,所以 i*16,对吗?)没有具体说明每个 Bucket 对象所需的偏移量。

那么,在位置 &base_pointer[i] 使用放置 new 时,它们不应该相同吗?我不明白这两种内存地址(m_baseMemory,base_pointer)如何彼此如此不同。当我将 base_pointer 地址与 base_pointer 地址加上分配的内存进行比较时,我应该得到一个大 80 的地址(十进制),但是当我比较数字时,它的差异是数百?一个例子: base_pointer 地址为:010FFA6C base_pointer 地址 + sizeof(Bucket) * NUM_OF_BUCKETS 为:010FFBAC

即使 sizeof(Bucket) * NUM_OF_BUCKETS = 80 将被解释为十六进制,它也会添加 128 (8*16),而不是像这里的情况那样添加 320。老实说,我不明白这是如何计算的,因此不胜感激。

谢谢。

【问题讨论】:

  • 对齐要求可能吗? Bucket 需要对齐,而 char 不需要。
  • 16 字节?你确定它不是 16 位(2 字节),因为这样会更有意义吗?
  • @TomaszPlaskota sizeof 返回 16,所以我猜这意味着 16 个字节,不是吗?
  • 听起来你不明白指向不同类型的指针的区别

标签: c++ pointers memory-management


【解决方案1】:

混淆的主要来源是您正在查看base_pointer 的地址,而您应该查看它的值。

您似乎错过的另一件事是,将k 添加到指针会将k + sizeof(what the pointer points to) 添加到地址。

&amp;base_pointer 是变量的地址,而不是分配的内存地址,所以&amp;base_pointer + sizeof(Bucket) * NUM_OF_BUCKETS 是距离它有80 * sizeof(Bucket*) 字节的地址。
80 * sizeof(Bucket*) 在 32 位目标上是 320。

您感兴趣的地址是base_pointerm_baseMemory + k * sizeof(Bucket)base_pointer + k 表示同一个地址,&amp;base_pointer[k] 也是。

【讨论】:

  • 谢谢,这给了我一些信息。但是为什么 m_baseMemory 和 base_pointer 仍然如此不同呢?我想这与转换为 Bucket 指针有关,但它究竟是如何工作的?我的意思是,它不能只将地址除以 Bucket 的大小或类似的东西,因为这会完全改变地址。
  • 另外,如果我输出 m_baseMemory(它是一个 char 指针,键入 char *),我会得到奇怪的符号,而不是地址。那是怎么回事?它不应该像base_pointer一样工作,它们都指向大致相同的地址吗?
  • @Grougal 试图澄清。 (如果你想打印它,请将指针指向void*。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-03
  • 1970-01-01
  • 2011-09-27
  • 2021-10-16
相关资源
最近更新 更多