c++ - 分区内存时的严格别名和对齐问题

标签 c++ pointers memory-management c++14

我的目标是分配单个内存块,然后将其划分为不同类型的较小数组。我对此处编写的代码有几个问题:

#include <iostream>
#include <cstdint>
#include <cstdlib>

int main() {
    constexpr std::size_t array_count   = 5;
    constexpr std::size_t elements_size = sizeof(std::uint32_t) + sizeof(std::uint16_t);

    void* const pv = std::calloc(array_count, elements_size);

    //Partition the memory. p32 array starts at pv, p16 array starts after the 20 byte buffer for the p32 array.
    std::uint32_t* const p32 = (std::uint32_t *) pv;
    std::uint16_t* const p16 = (std::uint16_t *)((char *) pv + sizeof(std::uint32_t) * array_count);

    //Initialize values.
    for(std::size_t i = 0; i < array_count; ++i) {
        p32[i] = i;
        p16[i] = i * 2;
    }

    //Read them back.
    for(std::size_t i = 0; i < array_count; ++i) {
        std::cout << p32[i] << std::endl;
        std::cout << p16[i] << std::endl;
        std::cout << std::endl;
    }

    std::free(pv);
}
  1. 此代码是否违反了 c++ 的严格别名规则?从 malloc 或 calloc 调用中转换指针时,我无法找到有关别名的资源。 p32 和 p16 指针不应重叠。
  2. 如果我颠倒两个数组的位置,其中 p16 从 pv 开始,而 p32 与 pv 有 10 字节的偏移量,这可能会导致段错误,因为 uint32_t 与 4 字节边界对齐 pv + 10 可能在 2 字节上边界,对吗?
  3. 这个程序是否不安全,或者引入了我通常遗漏的任何未定义行为?我在本地机器上得到了预期的输出,但这当然并不意味着我的代码是正确的。

最佳答案

是的,程序是UB。当您这样做时:

for(std::size_t i = 0; i < array_count; ++i) {
    p32[i] = i;
    p16[i] = i * 2;
}

p32p16 没有指向 uint32_tuint16_t 对象。 calloc 只是给你字节,而不是对象。您不能只是将 reinterpret_cast 对象变成存在。最重要的是,索引仅为数组定义,p32 不指向数组。

要使其定义明确,您必须创建一个数组对象。但是,数组的 placement-new 是 broken ,因此您需要手动初始化一堆 uint32_t,例如:

auto p32 = reinterpret_cast<uint32_t*>(pv);
for (int i = 0; i < array_count; ++i) {
    new (p32+i) uint32_t; // NB: this does no initialization, but it does satisfy
                          // [intro.object] in actually creating an object
}

这会遇到一个单独的问题:CWG 2182 .现在我们有 array_count uint32_t,但是我们没有 uint32_t[array_count] 所以索引仍然是 UB。基本上,完全按照标准的 C++ 来编写它是不可能的。另见 my similar question on the topic .


也就是说,在野外执行此操作的代码量是巨大的,并且每个实现都将允许您执行此操作。

关于c++ - 分区内存时的严格别名和对齐问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45617140/

相关文章:

c++ - 为什么这个 do-while-loop 每隔一个循环只写入数组?

c++ - 如何修复多重声明和多重初始化错误?

c++ - 从 C++ 到 AS3 : what are fundamental AS3 data structures classes?

c++ - 使用 SFML 处理多个客户端套接字

c++ - 分配大内存的最佳方法

c++ - 由于递归删除,智能指针炸毁堆栈

c++ - 确保给出一个不会变得无效的引用

c - 当我注释 malloc() 调用时,为什么会出现段错误(核心转储)?

c - 指向二维数组的指针

ios - 内存管理 - 如何在不创建新实例的情况下显示已实例化的 ViewController