Подтвердить что ты не робот

Какова цель иметь отдельный "оператор new []"?

Похож, что operator new и operator new[] имеют точно такую ​​же подпись:

void* operator new( size_t size );
void* operator new[]( size_t size );

и сделать то же самое: либо верните указатель на достаточно большой блок необработанной (не инициализированной в любом случае) памяти, либо выбросьте исключение.

Также operator new вызывается внутри, когда я создаю объект с new и operator new[] - при создании массива объектов с new[]. Тем не менее, вышеупомянутые две специальные функции вызываются С++ внутренне точно таким же образом, и я не вижу, как два вызова могут иметь разные значения.

Какова цель иметь две разные функции с точно такими же сигнатурами и точно такое же поведение?

4b9b3361

Ответ 1

В Design and Evolution of С++ (раздел 10.3) Страуступ упоминает, что если бы новый оператор для объекта X сам использовался для выделения массива объекта X, то писателю X:: operator new() пришлось бы иметь дело с распределением массива тоже, что не является общим использованием для new() и сложностью добавления. Таким образом, не рассматривалось использование new() для распределения массива. Тогда не было простого способа выделить разные области хранения для динамических массивов. Решение заключалось в предоставлении отдельных методов распределения и деаллокатора для массивов: new [] и delete [].

Ответ 2

Операторы могут быть переопределены (для определенного класса или в пространстве имен или во всем мире), и это позволяет вам предоставлять отдельные версии, если вы хотите рассматривать распределение объектов по-разному от распределения массивов. Например, вы можете выделить из разных пулов памяти.

Ответ 3

У меня был достаточно хороший взгляд на это, и быть тупым там нет причин с точки зрения интерфейса.

Единственная возможная причина, по которой я могу думать, - дать подсказку оптимизации для реализации, operator new[], вероятно, будет предложено выделить более крупные блоки памяти; но это действительно очень тонкое предположение, поскольку вы могли бы new создать очень большую структуру или new char[2], которая на самом деле не считается большой.

Обратите внимание, что operator new[] не добавляет лишней памяти для подсчета массива или чего-либо еще. Задача оператора new[] состоит в том, чтобы определить, сколько накладных расходов (если есть) необходимо и передать правильный счетчик байтов в operator new[].

[Тест с gcc указывает, что дополнительное содержимое не требуется new[], если только тип создаваемых элементов массива не имеет нетривиального дескриптора.]

С точки зрения интерфейса и контракта (кроме необходимости использования правильной соответствующей функции освобождения) operator new и operator new[] идентичны.

Ответ 4

Одна цель состоит в том, что они могут быть отдельно определены пользователем. Поэтому, если я хочу инициализировать память в одиночных выделенных кучей объектах до 0xFEFEFEFE и памяти в массивах, распределенных по кучам, до 0xEFEFEFEFEF, потому что я думаю, что это поможет мне с отладкой, тогда я могу.

Стоит ли это того, что это другое дело. Я думаю, если ваша конкретная программа в основном использует довольно маленькие объекты и довольно большие массивы, тогда вы можете выделить разные кучи в надежде, что это уменьшит фрагментацию. Но в равной степени вы могли бы определить классы, на которые вы выделяете большие массивы, и просто переопределить operator new[] для этих классов. Или operator new может переключаться между разными кучами на основе размера.

Фактически существует разница в формулировке требований. Один выделяет выделенную память для любого объекта указанного размера, другой выделяет выделенную память для любого массива указанного размера. Я не думаю, что есть какая-то разница - массив размером 1, несомненно, имеет такое же выравнивание, как и объект, но я мог ошибаться. Тот факт, что по умолчанию версия массива возвращает то же, что и версия объекта, предполагает, что разницы нет. Или, по крайней мере, требования к выравниванию объекта более строгие, чем требования к массиву, которые я не могу понять...

Ответ 5

Стандарт говорит, что new T вызывает operator new( ) и new T[ ] приводит к вызову operator new[]( ). Вы можете перегрузить их, если хотите. Я считаю, что нет никакой разницы между ними по умолчанию. Стандарт говорит, что они сменные (3.7.3/2):

Библиотека предоставляет определения по умолчанию для глобальных функций распределения и освобождения. Некоторые глобальные функции распределения и освобождения являются сменными (18.4.1). Программа C + + должна предоставлять не более одного определение сменной функции распределения или освобождения. Любое такое определение функции заменяет по умолчанию в библиотеке (17.4.3.4). Следующие функции распределения и освобождения (18.4) неявно объявляются в глобальной области видимости в каждой единицы перевода программы

void* operator new(std::size_t) throw(std::bad_alloc);  
void* operator new[](std::size_t) throw(std::bad_alloc);  
void operator delete(void*) throw();  
void operator delete[](void*) throw();