Какова цель наличия отдельного «оператора new []»? - PullRequest
12 голосов
/ 23 марта 2010

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

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

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

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

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

Ответы [ 5 ]

7 голосов
/ 23 марта 2010

Я достаточно неплохо на это посмотрю, и, если говорить прямо, нет причин с точки зрения интерфейса.

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

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

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

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

7 голосов
/ 23 марта 2010

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

6 голосов
/ 23 марта 2010

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

5 голосов
/ 23 марта 2010

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

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

1 голос
/ 23 марта 2010

Стандарт говорит, что 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();  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...