如果您写int *p = new int[SIZE_MAX];
,可以保证会发生什么?抛出异常了吗?还是有可能使用计算为operator new[]
的参数调用基础SIZE_MAX * sizeof(int)
函数,并可能发生未经检查的溢出(模减少)?
在C ++ 17(N4659)§6.9.2 [basic.compound]¶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];
}
目的是为了避免在优化但符合标准的实现中出现整数溢出,如果标准指出在这种情况下发生的事情是实现定义的(或未定义/未指定的行为),则该整数溢出可以在不检查模减少的情况下执行乘法)。
旁注:
答案 0 :(得分:2)
您引用的段落是关于类型的。
即您不能将T
的类型为sizeof(T) > SIZE_MAX
。这与new
无关,应该由编译器在编译阶段进行诊断。
new
的行为在不同的地方进行了解释。
从C ++ 11开始,存在一个特殊的异常类型std::bad_array_new_length
,如果大小错误,实现应抛出该异常。这是标准中的相关报价:
在以下情况下,noptr-new-declarator中的表达式是错误的:
- (8.1)该表达式为非类类型,在转换为std :: size_t之前其值小于零;
- (8.2)该表达式是类类型,并且在应用第二个标准转换([over.ics.user])之前其值小于 零;
- (8.3),其值应使分配的对象的大小超过实现定义的限制;或
- (8.4)new-initializer是一个括号初始化列表,以及为其提供初始化程序的数组元素的数量(包括 在字符串文字中以“ \ 0”结尾)超过了元素数量 进行初始化。
如果将表达式转换为std :: size_:t:
后错误
- (8.5) 如果表达式是核心常量表达式,则程序格式错误;
- (8.6) 否则,不调用分配函数。代替
- (8.6.1) 如果将要调用的分配函数具有非抛出异常规范([except.spec]),则 new-expression是所需结果类型的空指针值;
- (8.6.2) 否则,new表达式将通过抛出与以下类型的处理程序([except.handle])相匹配的类型的异常来终止 输入std ::: bad_array_new_length。
所以这是预期的行为。但是,请记住,您的operator new
重载只会收到最终的size_t
(即在所有计算之后),因此您不需要/不需要进行模减少。
在实现自己的operator new
(8.5)时,应由编译器处理,而您只需要处理(8.6)。