Ответ
Оператор new в C++ не «понимает» размер динамически. Размер вычисляется на этапе компиляции на основе типа и передается в низкоуровневую функцию выделения памяти.
Механизм работы new T:
- Компилятор вычисляет
sizeof(T)с учетом выравнивания (alignof(T)). - Генерируется вызов глобальной функции
void* operator new(std::size_t count), куда передается вычисленный размер. - Эта функция запрашивает
countбайт у менеджера памяти ОС (например, черезmallocили системный вызов). - Если тип
Tимеет нетривиальный конструктор, компилятор затем вызывает его для инициализации памяти.
Пример для массива new T[n]:
MyClass* arr = new MyClass[10];
Компилятор вычислит общий размер как:
total_size = sizeof(MyClass) * 10 + возможный_оверхед.
Оверхед может потребоваться для хранения размера массива (чтобы delete[] знал, сколько деструкторов вызвать).
На практике:
int* p1 = new int; // Выделяет sizeof(int) байт (например, 4)
double* p2 = new double[5]; // Выделяет 5 * sizeof(double) байт (например, 5*8=40)
struct alignas(16) Vec4 { float x, y, z, w; };
Vec4* vec = new Vec4; // Выделяет 16 байт с выравниванием 16
Важные детали:
- Размер известен компилятору:
sizeof— это оператор времени компиляции. - Выравнивание: Память выделяется с учетом
alignof(T). Неправильное выравнивание может привести к падению производительности (на x86) или к ошибке (на ARM). - Placement new:
new (buffer) T()— не выделяет память, а только конструирует объект в предоставленном буфереbuffer. Размер типа все равно известен компилятору. - Пользовательский
operator new: Можно переопределить, чтобы управлять выделением, но ему все равно передается готовый размер.