Какова цель наличия отдельного “оператора, нового []”?

Похож operator new и operator new[] имейте точно ту же подпись:

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

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

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

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

12
задан sharptooth 25 March 2010 в 11:12
поделиться

5 ответов

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

6
ответ дан 2 December 2019 в 05:54
поделиться

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

7
ответ дан 2 December 2019 в 05:54
поделиться

Стандарт говорит, что new T вызывает оператор new () и new T [] приводит к вызову оператора 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 delete (void *) throw (); 
оператор void delete [] (void *) throw (); 
 
1
ответ дан 2 December 2019 в 05:54
поделиться

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

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

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

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

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

7
ответ дан 2 December 2019 в 05:54
поделиться

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

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

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

5
ответ дан 2 December 2019 в 05:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: