Что гарантированно произойдет, если вы напишите 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];
}
Цель состоит в том, чтобы избежать целочисленного переполнения в оптимизированной, но стандартной соответствующей реализации, которая может выполнять умножение без проверки на уменьшение по модулю, если стандарт говорит, что то, что происходит в этом случае, определяется реализацией (или неопределенным / неуказанным поведением ).
Примечания:
- Я говорю «переполнение», хотя целочисленные типы без знака не переполняются. Это означает «уменьшение по модулю» в этом посте.
- new-expression определено в C ++ 17 ( N4659 ) § 8.3.4 [expr.new] ¶ 1.
- Это вопрос «языкового адвоката».