new表达式中内存分配与初始化器求值的顺序是否有明确定义?
咱们来逐个拆解这两个关于C++ new表达式的问题,都是很重要的底层细节:
问题1:new表达式中,初始化器是否在内存分配完成后才求值?
答案是明确肯定的,C++标准对new表达式的执行流程有严格的顺序定义:
- 第一步:先完成底层内存分配(通过
operator new或其重载版本); - 第二步:只有在内存分配成功之后,才会对初始化器进行求值,并用它来在分配好的内存上构造对象。
不存在内存分配还没完成,初始化器就先被求值的情况,这个顺序是绝对串行、明确定义的。
问题2:auto p = new T( U(std::move(v)) );的求值顺序与异常安全性
这个场景下的求值顺序同样是明确定义的,完全遵循上面的规则:
- 先执行内存分配(调用
operator new); - 只有当内存分配成功后,才会求值
U(std::move(v))——也就是先把v移动构造出一个U临时对象,再用这个U对象作为参数构造T对象。
结合题目里的前提(T( U(std::move(v)) )不会抛出异常),这个代码确实具备强异常安全性:
- 如果内存分配抛出异常(比如分配失败),此时
std::move(v)根本还没执行,v的状态完全保持原样,没有任何副作用; - 一旦内存分配成功,后续的初始化过程不会抛出异常,最终p会指向一个合法的T对象,同时v的移动操作也已经完成。
简单说就是:要么操作完全成功(v被移动,p持有有效对象),要么完全回滚(内存分配失败,v毫无变化),不会出现“v已经被移动但内存分配失败”的糟糕中间状态。
内容的提问来源于stack exchange,提问作者Lingxi
相关产品推荐
相关产品推荐

