Разница между new и malloc в C++

искусственный интеллект

 

Разница между new и malloc

1. Расположение запрашиваемой памяти

Новый оператор динамически выделяет память для объектов из свободного хранилища, а функция malloc динамически выделяет память из кучи. Свободная область хранения — это абстрактное понятие, основанное на операторе new в C++.Всякий раз, когда с помощью оператора new создается приложение памяти, память является свободной областью хранения. Куча — это термин в операционной системе.Это специальный участок памяти, поддерживаемый операционной системой для динамического выделения памяти программ.Язык C использует malloc для выделения памяти из кучи и использует free для освобождения выделенной соответствующей памяти .

Таким образом, может ли свободная область хранения быть кучей (вопрос эквивалентен тому, может ли new динамически выделять память в куче), зависит от деталей реализации оператора new. Свободной областью хранения может быть не только куча, но и статическая область хранения, в зависимости от того, где оператор new выделяет память для объекта.

В частности, new даже не выделяет память для объекта! Функция поиска новых может сделать это:

new (place_address) type

place_address — это указатель, представляющий адрес участка памяти. При использовании вышеуказанного вызова нового оператора только с одним адресом новый оператор вызывает специальный оператор new, который представляет собой следующую версию:

void * operator new (size_t,void *) //不允许重定义这个版本的operator new

Этот оператор new не выделяет никакой памяти, он просто возвращает аргумент-указатель, а правильное новое выражение отвечает за инициализацию объекта по адресу, указанному в place_address.

2. Безопасность возвращаемого типа

При успешном выделении памяти оператором new он возвращает указатель на объектный тип.Тип строго соответствует объекту, преобразование типов не требуется.Поэтому new — это оператор, соответствующий безопасности типов. Успешное выделение памяти malloc возвращает void *, который нужно преобразовать в нужный нам тип, приведя указатель void*.
Типобезопасность во многом эквивалентна безопасности памяти.Типобезопасный код не будет пытаться получить доступ к областям памяти, которые не авторизованы им самим. Можно еще многое сказать о безопасности типов в C++.

3. Возвращаемое значение при сбое выделения памяти

Когда новое выделение памяти не удается, будет сгенерировано исключение bac_alloc, и оно не вернет NULL; если malloc не сможет выделить память, оно вернет NULL.
При использовании языка C мы привыкли судить об успешном выделении памяти после того, как malloc выделит память:

int *a  = (int *)malloc ( sizeof (int ));
if(NULL == a)
{
    ...
}
else 
{
    ...
}

Новички в лагере C++ из языка C могут привнести эту привычку в C++:

int * a = new int();
if(NULL == a)
{
    ...
}
else
{   
    ...
}

На самом деле нет никакого смысла делать это, потому что new вообще не вернет NULL, и программа может выполнить оператор if, чтобы указать, что выделение памяти прошло успешно, а в случае неудачи будет сгенерировано исключение. Правильный подход должен заключаться в использовании механизма исключений:

try
{
    int *a = new int();
}
catch (bad_alloc)
{
    ...
}

Кстати, если вы хотите понять основы исключений, вы можете увидетьБлог Woo Woo.cn на.com/Q G-Wuhan Station/Afraid/51…Анализ механизма исключений C++.

4. Нужно ли указывать объем памяти

При использовании оператора new для подачи заявки на выделение памяти не нужно указывать размер блока памяти, компилятор рассчитает его на основе информации о типе, а malloc нужно явно указать размер требуемой памяти.

class A{...}
A * ptr = new A;
A * ptr = (A *)malloc(sizeof(A)); //需要显式指定所需内存大小sizeof(A);

Конечно, мне не подходит использование malloc для выделения памяти для нашего пользовательского типа, см. следующий.

5. Следует ли вызывать конструктор/деструктор

Существует три шага при использовании оператора new для выделения памяти объекта:

  • Шаг 1. Вызовите новую функцию оператора (оператор new[] для массивов), чтобы выделить достаточно большое необработанное безымянное пространство памяти для хранения объектов определенного типа.
  • Шаг 2: Компилятор запускает соответствующий конструктор для создания объекта и передает ему начальное значение.
  • Часть 3. После создания объекта возвращается указатель на объект.

Существует два шага при использовании оператора удаления для освобождения памяти объекта:

  • Шаг 1: Вызовите деструктор объекта.
  • Шаг 2: Компилятор вызывает функцию удаления оператора (или оператора удаления []), чтобы освободить место в памяти.

Короче говоря, new/delete вызовет конструктор/деструктор объекта для завершения создания/уничтожения объекта. А malloc нет. Если вы не слишком многословны, вот мой пример:

class A
{
public:
    A() :a(1), b(1.11){}
private:
    int a;
    double b;
};
int main()
{
    A * ptr = (A*)malloc(sizeof(A));
    return 0;
}

Установите точку останова при возврате и просмотрите содержимое памяти, на которую указывает ptr:

 

Видно, что конструктор по умолчанию для A не был вызван, потому что значения элементов данных a и b не были инициализированы, поэтому я сказал выше, что использование malloc/free для обработки пользовательских типов в C++ недопустимо. На самом деле, это не только пользовательский Type, любой тип в стандартной библиотеке, который нужно построить/разрушить, вообще не подходит.

И при использовании new для выделения объекта:

int main()
{
    A * ptr = new A;
}

Глядя на ассемблерный код, сгенерированный программой, можно обнаружить, что вызывается конструктор A по умолчанию:

 

 

6. Обработка массивов

C++ предоставляет new[] и delete[] для конкретной обработки типов массивов:

A * ptr = new A[10];//分配10个A对象

Память, выделенная с помощью new[], должна быть освобождена с помощью delete[]:

delete [] ptr;

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

Что касается malloc, то он не знает массив, который вы хотите поместить в этот кусок памяти или что-то еще, в любом случае, он дает вам кусок необработанной памяти, и это делается после предоставления вам адреса памяти. Поэтому, если мы хотим динамически выделять память массива, нам также нужно вручную настроить размер массива:

int * ptr = (int *) malloc( sizeof(int) );//分配一个10个int元素的数组

7. Могут ли new и malloc вызывать друг друга?

Реализация оператора New/оператора Delete может быть основана на Malloc, а реализация Malloc не может вызывать New. Ниже приведен простой способ написания Operator New/Operator Delete, другие варианты также аналогичны:

void * operator new (sieze_t size)
{
    if(void * mem = malloc(size)
        return mem;
    else
        throw bad_alloc();
}
void operator delete(void *mem) noexcept
{
    free(mem);
}

8. Может ли он быть перегружен?

оператор new/delete может быть перегружен. Стандартная библиотека определяет 8 перегруженных версий операторов new и delete:

//这些版本可能抛出异常
void * operator new(size_t);
void * operator new[](size_t);
void * operator delete (void * )noexcept;
void * operator delete[](void *0)noexcept;
//这些版本承诺不抛出异常
void * operator new(size_t ,nothrow_t&) noexcept;
void * operator new[](size_t, nothrow_t& );
void * operator delete (void *,nothrow_t& )noexcept;
void * operator delete[](void *0,nothrow_t& )noexcept;

Мы можем настроить любую из вышеперечисленных версий функций при условии, что пользовательская версия должна находиться в глобальной области видимости или области действия класса. Вещи, которые слишком подробно описаны здесь, не описаны.Короче говоря, мы знаем, что у нас достаточно свободы, чтобы перегрузить оператор new/оператор delete, чтобы решить, как наши new и delete будут выделять память для объектов и как перерабатывать объекты.

А malloc/free не допускает перегрузки.

9. Возможность интуитивного перераспределения памяти

После использования памяти, выделенной malloc, если вы обнаружите, что памяти недостаточно во время использования, вы можете использовать функцию realloc для перераспределения памяти для расширения памяти. realloc сначала оценивает, достаточно ли непрерывного пространства в памяти, на которую указывает текущий указатель, и если да, расширяет выделенный адрес памяти на месте и возвращает исходный адресный указатель; если места недостаточно, сначала выделяет место в соответствии с вновь указанным размер, данные копируются от начала до конца во вновь выделенную область памяти, а затем освобождается исходная область памяти.

new не имеет такого интуитивно понятного вспомогательного средства для расширения памяти.

10. Клиент обрабатывает недостаточное выделение памяти

Прежде чем оператор new создаст исключение, отражающее неудовлетворенную потребность, он вызывает указанный пользователем обработчик ошибок, new-handler. new_handler — это тип указателя:

namespace std
{
    typedef void (*new_handler)();
}

Указывает на функцию без параметров и без возвращаемого значения, то есть на функцию обработки ошибок. Чтобы указать функцию обработки ошибок, клиенту необходимо вызвать set_new_handler, стандартную библиотечную функцию, объявленную в:

namespace std
{
    new_handler set_new_handler(new_handler p ) throw();
}

Параметр set_new_handler — это указатель new_handler, который указывает на функцию, которая будет вызываться, когда оператор new не может выделить достаточно памяти. Возвращаемое значение также является указателем на функцию new_handler, которая выполнялась (но должна была быть заменена) до вызова set_new_handler.

С помощью malloc клиент не может программно решать, что делать, когда не хватает памяти для выделения, и может только наблюдать, как malloc возвращает NULL.

Суммировать

Расположите 10-балльные различия, описанные выше, в таблицу:

особенность new/delete malloc/free
Где выделить память свободное место для хранения куча
Возвращаемое значение ошибки выделения памяти указатель полного типа void*
Возвращаемое значение ошибки выделения памяти Выдает исключение по умолчанию вернуть NULL
размер выделенной памяти Вычисляется компилятором на основе типа Количество байтов должно быть указано явно
работать с массивами Существует новая версия new[], которая обрабатывает массивы. Требует от пользователя вычисления размера массива для выделения памяти
Расширение выделенной памяти не может быть обработан интуитивно Просто сделать с realloc
звонить ли друг другу Да, см. конкретную реализацию оператора new/delete не вызываемый новый
Недостаточно памяти при выделении памяти Клиенты могут указывать функции обработчика или переформулировать распределители. Невозможно обработать с помощью пользовательского кода
перегрузка функций позволять не допускается
Конструктор и деструктор перечислить не звони

То, что дает вам malloc, похоже на кусок первобытной земли: то, что вы хотите посадить, нужно посадить на земле самому.

 

И новый помогает вам разделить поле (массив), сеет семена для вас (конструктор) и предоставляет вам другие возможности для использования:

 

Конечно, malloc нельзя сказать, что он уступает new, у каждого из них есть свои применимые места. В языке с большим количеством ООП, таком как C++, более уместно использовать new/delete.

Вот краткий обзор new и delete, а затем более подробная информация о разнице между new и malloc.

1. создать и удалить
Язык C предоставляет две системные функции, malloc и free, для завершения работы приложения и освобождения динамической памяти. C++ предоставляет два ключевых слова new и delete;

1.1 Правила
new/delete — ключевое слово, более эффективное, чем malloc и free.
Используйте парами, чтобы избежать утечек памяти и многократного освобождения.
Избегайте перекрестного использования, такого как удаление пространства приложения malloc, новое пространство бесплатно.
new/delete в основном используется для применения и выпуска объектов класса. При применении будет вызван конструктор для завершения инициализации, а при освобождении будет вызван деструктор для завершения очистки памяти.
1.2 новое/новое[] использование
// открываем единое адресное пространство
int *p = new int; // открываем пробел размером sizeof(int)
int *q = new int(5); //Создаем пространство sizeof(int) и инициализируем его значением 5.
// освобождаем место в массиве
//Одномерный
int *a = new int[100]{0};//Открываем целочисленный массив размером 100 и инициализируем его значением 0.
// двухмерный
int (*a)[6] = new int[5][6];
//3D
int (*a)[5][6] = new int[3][5][6];
//4-х мерные и выше и так далее.
1.3 удалить/удалить [] использование
// освобождаем одно целое пространство
int *a = new int;
delete a;
// освобождаем место в массиве
int *b = new int[5];
delete []b;
Во-вторых, разница между new и malloc
2.1 Свойства
new и delete являются ключевыми словами C++ и нуждаются в поддержке компилятора; malloc и free являются библиотечными функциями и нуждаются в поддержке заголовочного файла.

2.2 Параметры
При использовании оператора new для подачи заявки на выделение памяти не нужно указывать размер блока памяти, компилятор рассчитает его на основе информации о типе. И malloc нужно явно указать размер требуемой памяти.

2.3 Тип возврата
При успешном выделении памяти оператором new он возвращает указатель на объектный тип.Тип строго соответствует объекту, преобразование типов не требуется.Поэтому new — это оператор, соответствующий безопасности типов. Успешное выделение памяти malloc возвращает void *, который нужно преобразовать в нужный нам тип, приведя указатель void*.

2.4 Пользовательские типы
new сначала вызовет новую функцию оператора, чтобы применить достаточно памяти (обычно реализуется с помощью malloc на нижнем уровне). Затем вызовите конструктор типа, инициализируйте переменные-члены и, наконец, верните указатель пользовательского типа. delete сначала вызывает деструктор, а затем вызывает функцию удаления оператора для освобождения памяти (обычно используя free внизу).

malloc/free — это библиотечная функция, которая может только динамически запрашивать и освобождать память, и ее нельзя заставить выполнять создание и уничтожение объектов пользовательского типа.

2.5 «Перегрузка»
C++ позволяет создавать собственные операторы new и операторы delete для управления динамическим выделением памяти.

2.6 Область памяти
new делает две вещи: выделяет память и вызывает конструктор класса, а delete — вызывает деструктор класса и освобождает память. В то время как malloc и free просто выделяют и освобождают память.

Новый оператор динамически выделяет память для объектов из свободного хранилища, а функция malloc динамически выделяет память из кучи. Свободная область хранения — это абстрактное понятие, основанное на операторе new в C++.Всякий раз, когда с помощью оператора new создается приложение памяти, память является свободной областью хранения. Куча — это термин в операционной системе.Это специальный участок памяти, поддерживаемый операционной системой для динамического выделения памяти программ.Язык C использует malloc для выделения памяти из кучи и использует free для освобождения выделенной соответствующей памяти . Свободная область хранения не равна куче, как упоминалось выше, новый макет не обязательно должен быть в куче.

2.7 Распределение не удалось
Когда новое выделение памяти не удается, будет сгенерировано исключение bac_alloc. Возвращает NULL, когда malloc не может выделить память.

2.8 Утечки памяти
Утечки памяти могут быть обнаружены как new, так и malloc, и new может указать, какая строка какого файла это, но malloc не может.

Справочная статья:

Разница между C++ new и malloc 

В чем разница между c++ new и malloc — ywliao — Blog Park (cnblogs.com)