placement new构造数组时不能用new[]语法,必须手动逐个调用placement new并配合std::launder获取合法指针,析构也需反向手动调用,且严禁使用delete[]。

placement new 构造数组时不能直接用 new[] 语法
标准 C++ 不允许对 placement new 使用 operator new[](size_t, void*) 形式的数组版本——它根本没被定义。你写 new (buf) int[10] 看似合法,实际调用的是 operator new[](size_t)(带 size 的全局版本),不是 placement 版本,这会导致未定义行为,且内存不会在 buf 上构造。
- 编译器通常不报错,但运行时对象未被正确构造(
int类型可能看似正常,但自定义类型会跳过构造函数) - 必须手动逐个调用构造函数,配合
std::launder(C++17 起)获取合法指针 - 析构也必须手动逐个调用,顺序与构造相反
手动构造对象数组的正确步骤
以 char buf[sizeof(MyClass) * N] 为例,构造 N 个 MyClass 对象:
MyClass* ptr = reinterpret_cast<myclass>(buf);
for (int i = 0; i <ul>
<li>不能依赖 <code>buf</code> 直接转成 <code>MyClass*</code> 后当数组用(违反严格别名规则)</li>
<li>
<code>std::launder</code> 不是可选优化:若后续通过该指针读写对象,不加它可能被编译器优化掉访问</li>
<li>如果 <code>MyClass</code> 有非平凡构造函数,漏掉任意一次 <code>new (ptr+i) MyClass(...)</code> 就意味着那个对象未构造</li>
</ul>
<h3>析构时必须反向手动调用,且不能 delete[]</h3>
<p>placement new 构造的对象,永远不能用 <code>delete[]</code> 或 <code>delete</code>;否则会尝试调用全局 <code>operator delete[]</code>,而它并不知道你用的是哪块内存,大概率崩溃或静默损坏。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill4025" title="C++ 算法竞赛自动化测试数据生成与校验框架"><img
src="https://img.php.cn/upload/skill/000/000/081/178988956499722.jpg" alt="C++ 算法竞赛自动化测试数据生成与校验框架" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill4025" title="C++ 算法竞赛自动化测试数据生成与校验框架" class="overflowclass">C++ 算法竞赛自动化测试数据生成与校验框架</a>
<p class="overflowclass">根据原题生成新题面、验证器及完整测试数据,自动套用 testlib 模板,用于用户要求生成测试数据时。</p>
</div>
<a rel="nofollow" href="/xiazai/skill4025" title="C++ 算法竞赛自动化测试数据生成与校验框架" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<pre class="brush:php;toolbar:false;">for (int i = N - 1; i >= 0; --i) {
(ptr + i)->~MyClass(); // 显式调用析构函数
}
- 析构顺序必须和构造顺序相反(栈语义),尤其当对象间有依赖时
- 对
int这类 trivial 类型,调用析构函数无效果,但写法要统一,避免后期替换为非 trivial 类型时遗漏 -
buf本身由你分配(malloc、aligned_alloc或栈数组),析构后可复用或free,但绝不经由delete释放
对齐和内存布局容易被忽略
placement new 要求目标地址满足类型的对齐要求。例如 alignof(std::max_align_t) 是常见底线,但像 std::optional<__m256></__m256> 可能需要 32 字节对齐。用错对齐,构造可能 SIGBUS(ARM)或静默错误(x86)。
- 别直接用
char buf[1024]—— 栈上数组不一定按需对齐;改用alignas(32) char buf[1024] - 用
std::aligned_alloc分配时,第一个参数必须 ≥ 所需对齐值,且返回指针本身已对齐 - 检查是否对齐:
if (reinterpret_cast<uintptr_t>(buf) % alignof(MyClass) != 0)</uintptr_t>,不满足就别往下走
真正麻烦的从来不是语法,而是构造/析构的完整性、对齐的隐蔽性、以及 std::launder 那种“不加也不报错但随时翻车”的特性。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










