在 int 数组的情况下,新表达式可以"overflow"吗?

Can a new-expression "overflow" in the case of an array of int?

本文关键字:overflow 表达式 数组 int 情况下      更新时间:2023-10-16

如果编写int *p = new int[SIZE_MAX];,保证会发生什么?是否引发异常?或者,调用底层operator new[]函数时,参数计算为SIZE_MAX * sizeof(int),可能存在未检查的溢出(模减少)?

在C++17(N4659)§6.9.2[碱性化合物]¶2:中

构造一个类型,使其对象表示中的字节数超过类型std::size_t(21.2)中可表示的最大值是错误的。

"格式错误"类型的后果是什么?未定义的行为?

假设sizeof(int)大于1。下面的程序是否格式良好,并保证抛出异常?

#include <cstdint> // SIZE_MAX
#include <cstddef> // std::size_t
int main() {
std::size_t size_max = (SIZE_MAX);
int *pointer = new int[size_max];
}

还是必须执行以下溢出检测?

#include <cstdint> // SIZE_MAX
#include <cstddef> // std::size_t
#include <new>     // std::bad_alloc
bool mul_overflow (std::size_t a, std::size_t b) {
std::size_t size_max = (SIZE_MAX);
return a > (size_max / b);
}
int main() {
std::size_t size_max = (SIZE_MAX);
if (mul_overflow (size_max, sizeof(int)))
throw std::bad_alloc ();
int *pointer = new int[size_max];
}

其目的是在优化但符合标准的实现中避免整数溢出,如果标准规定在这种情况下发生的是实现定义的(或未定义/未指定的行为),则该实现可以在不检查模缩减的情况下执行乘法。

旁注:

  • 我说"溢出",即使无符号整数类型不会溢出。这篇文章的意思是"模减少">
  • 新表达式在C++17(N4659)§8.3.4[expr.new]¶1中定义
  • 这是一个"语言律师"的问题

您引用的段落谈论类型

也就是说,T不能与sizeof(T) > SIZE_MAX一起使用。这与new无关,应该由编译器在编译阶段进行诊断。

CCD_ 10的行为在不同的地方得到了解释。由于C++11,存在特殊的异常类型std::bad_array_new_length,如果大小错误,则实现应该抛出该异常类型。这是标准的相关报价:

[expr.new]

noptr新声明符中的表达式是错误的,如果:

  • (8.1)表达式为非类类型,并且在转换为std::size_­t之前其值小于零
  • (8.2)表达式为类类型,并且在应用第二个标准转换([over.ics.user])之前其值小于零
  • (8.3)其值使得所分配对象的大小将超过实现定义的限制;或
  • (8.4)新的初始化器是一个支持的init列表,并且为其提供初始化器的数组元素的数量(包括在字符串文字中终止"\0")超过元素数以进行初始化

如果转换为std::size_­t:后表达式错误

  • (8.5)如果表达式是核心常量表达式,则程序格式错误
  • (8.6)否则,不调用分配函数;相反
    • (8.6.1)如果本应调用的分配函数具有非抛出异常规范(〔except.spec〕),则new表达式是所需结果类型的空指针值
    • (8.6.2)否则,新表达式将通过抛出与的处理程序([axcept.handle])匹配的类型的异常而终止std型​::​坏排列新长度

所以这是预期行为。但是,请记住,您的operator new过载只会接收到最终的size_t(即,在所有计算之后),因此您不需要/不能进行模归约。

当实现您自己的operator new(8.5)时,编译器应该负责,您只需要负责(8.6)