You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++严格别名规则在数组与动态分配内存中的作用机制探讨

关于C++严格别名与对象生命周期的问题分析

我找不到涵盖严格别名规则所有边缘情况的资料。我理解在C++中访问特定地址上不存在的对象属于未定义行为(UB),比如把uint32_t*转换成float*并访问是非法的,因为该地址没有存活的float对象,而启动这类对象生命周期的唯一方式是使用placement new,简单赋值并不足够。基于此我有以下问题:

// CASE 1
uint64_t arr[8] = {}; //每个元素的动态类型现在是uint64_t?

for(int ii = 0; ii < 8; ++ii){
    new (arr+ii) double(3.14); //动态类型现在变成double?
}

arr[0] = 10; //以uint64_t类型解引用,但动态类型是double?我猜这违反严格别名规则?


// CASE 2
uint64_t* arr = new uint64_t[8]; //每个元素的动态类型现在是uint64_t?

// CASE 3
uint64_t* mal_arr = (uint64_t*)malloc(8*sizeof(uint64_t)); //动态类型现在是void?

mal_arr[0] = 10; //如果确实是void,这肯定非法,对吗?

逐个案例分析

CASE 1

  • 初始行uint64_t arr[8] = {};:每个元素的动态类型确实是uint64_t,数组初始化会直接创建8个uint64_t对象并置零。
  • 循环中的new (arr+ii) double(3.14);:placement new会在原有uint64_t对象的地址上构造double对象,这会自动结束原uint64_t对象的生命周期,此时每个数组位置的动态类型变为double。
  • arr[0] = 10;:这里是通过uint64_t类型的左值去访问动态类型为double的对象,确实违反了严格别名规则,属于未定义行为。严格别名规则明确:除非是字符类型(char/unsigned char/std::byte)这类允许的例外,否则不能用与对象动态类型不匹配的类型去访问它。

CASE 2

uint64_t* arr = new uint64_t[8];:每个元素的动态类型就是uint64_t。new[]会为8个uint64_t对象分配内存并完成初始化(内置类型默认值为0),此时静态类型和动态类型完全匹配,没有问题。

CASE 3

  • uint64_t* mal_arr = (uint64_t*)malloc(8*sizeof(uint64_t));:malloc只分配原始内存,不会创建任何对象,所以不存在“动态类型为void”的说法——void根本不是对象类型。
  • mal_arr[0] = 10;:这行代码的合法性分版本:
    • C++20之前:属于未定义行为,因为此时内存上没有uint64_t对象,直接赋值访问相当于操作一个不存在的对象。必须先用placement new构造对象,比如new(mal_arr) uint64_t(10);才能合法访问。
    • C++20及以后:新增了隐式对象创建规则,对于像uint64_t这样的平凡可析构类型,直接赋值会自动在内存上隐式创建对象,此时这行代码是合法的。

内容的提问来源于stack exchange,提问作者arc31

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 02:25:04