std::aligned_storage 在 c++17 已弃用、c++23 彻底移除,应改用 std::aligned_alloc 或 operator new(size, align_val_t) 配套对应 delete,并确保对齐值与目标类型 alignof(t) 一致、申请释放参数严格匹配。

std::aligned_storage 在 C++17 里已经弃用了,别硬用
它在 C++17 被标记为 deprecated,C++23 彻底移除。现在写新代码还手动拼 std::aligned_storage,大概率是在踩过时的坑——比如用 sizeof 和 alignof 算偏移、手写 placement new、漏掉 std::destroy_at,最后内存没析构或对齐错位,UB(未定义行为)悄无声息。
替代方案很明确:优先用 std::aligned_alloc(C++17 起)或 operator new(std::size_t, std::align_val_t)(C++17 起),它们直接返回对齐指针,语义清晰、生命周期可控。
-
std::aligned_alloc需要手动std::free,且分配大小必须是alignment的整数倍 -
operator new(size, align_val_t)配套operator delete(ptr, align_val_t),和普通 new/delete 一样支持异常安全 - 如果只是临时存一个对象(比如实现简易 variant),用
std::byte[sizeof(T)]+alignas(T)更轻量,但得自己管构造/析构
operator new(std::size_t, std::align_val_t) 怎么配对释放?
很多人只记得申请,忘了释放必须显式传 std::align_val_t,否则调用的是普通 operator delete(void*),导致内存泄漏或崩溃。
错误示范:auto p = ::operator new(1024, std::align_val_t{16}); ::operator delete(p); —— 这里 delete 没传对齐参数,行为未定义。
立即学习“C++免费学习笔记(深入)”;
- 正确释放:用
::operator delete(p, std::align_val_t{16}); - 对齐值必须和申请时一致,不能靠
alignof(T)临时算——因为T可能被优化掉,或者你根本没类型(比如纯缓冲区) - 如果封装成 RAII 类,
delete必须在析构函数里带上对齐参数,不能省
std::aligned_storage_t 的对齐值 A 不等于实际需要的对齐
这是最容易误判的一点:std::aligned_storage_t 只保证至少 8 字节对齐,但如果你要放 std::max_align_t 对齐的类型(比如某些 SIMD 类型),8 就不够——运行时可能 SIGBUS 或静默数据损坏。
真正该用的对齐值,是目标类型的 alignof(T),不是随便拍一个数字。
- 例如放
struct alignas(32) Vec32 { ... };,就得用alignas(32)或std::aligned_storage_t<sizeof></sizeof>(C++17 前) - 注意:某些平台(如 ARM64)对 16 字节以上对齐有额外要求,
alignof(std::max_align_t)可能只有 16,但__m256要求 32——这时必须显式指定 -
std::aligned_storage不检查你传的A是否合法,传错就直接 UB,编译器几乎不报错
为什么不用 malloc + posix_memalign?
在 Linux/macOS 上确实能用 posix_memalign,但它不是 C++ 标准,Windows 得换 _aligned_malloc,跨平台封装麻烦;更重要的是,它绕过了 C++ 的内存模型和分配器协议。
比如你在自定义 std::allocator 里混用 posix_memalign,迭代器失效、容器 resize 行为可能异常——标准库不保证兼容。
- 坚持用 C++ 原生接口:
operator new(size, align_val_t)是标准、可重载、可 hook 的 - 若需池化或定制策略,继承
std::pmr::memory_resource,而不是在裸指针上打补丁 - 调试时,
operator new的调用栈更干净,malloc堆栈容易被 libc 层掩盖
对齐这件事,核心就两条:申请和释放对齐参数严格一致;对齐值由目标类型决定,不是凭经验估。其它都是围绕这两条打转。










