В каких случаях использовать malloc и / или new?

Я вижу, что в C++ существует несколько способов выделения и освобождения данных, и я понимаю, что когда вы вызываете malloc, вы должны вызвать free, а когда вы используете оператор new, вы должны соединиться с delete, и смешивать их будет ошибкой (например, вызов free() на то, что было создано с помощью оператора new), но я не понимаю, когда мне следует использовать malloc / free, а когда я должен использовать new / delete в моих реальных программах.

Если вы эксперт по C++, сообщите мне о любых практических правилах или соглашениях, которым вы следуете в этом отношении.

Хорошие ответы, все, что я должен добавить (чего я не видел), это то, что new / delete вызывает для вас конструктор / деструктор, а malloc / free - нет. Просто стоит упомянуть разницу.

Bill K 09.10.2008 00:07

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

nsayer 08.10.2008 23:53

В современном C++ я все еще пытаюсь найти причину для использования того и другого.

Rahly 22.12.2017 22:53

Или используйте ни то, ни другое и используйте std: shared_ptr <T>. Тогда вам вообще не нужно удалять.

Vincent 27.02.2018 02:52
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
522
4
293 883
19

Ответы 19

Если вы не вынуждены использовать C, вам следует никогда не использоватьmalloc. Всегда используйте new.

Если вам нужен большой кусок данных, просто сделайте что-нибудь вроде:

char *pBuffer = new char[1024];

Будьте осторожны, хотя это неверно:

//This is incorrect - may delete only one element, may corrupt the heap, or worse...
delete pBuffer;

Вместо этого вы должны сделать это при удалении массива данных:

//This deletes all items in the array
delete[] pBuffer;

Ключевое слово new - это способ сделать это в C++, и оно гарантирует, что ваш тип будет иметь свой конструктор называется. Ключевое слово new также больше типобезопасный, тогда как malloc вообще не является типобезопасным.

Единственный способ, которым я мог подумать, что было бы полезно использовать malloc, - это если вам нужно изменить размер вашего буфера данных. У ключевого слова new нет аналогичного пути, как у realloc. Функция realloc может более эффективно увеличить размер блока памяти.

Стоит отметить, что нельзя смешивать new / free и malloc / delete.

Примечание. Некоторые ответы на этот вопрос неверны.

int* p_scalar = new int(5);  // Does not create 5 elements, but initializes to 5
int* p_array  = new int[5];  // Creates 5 elements

Что касается вызова delete foo, когда вы должны вызвать delete [] foo, некоторые компиляторы исправят это автоматически, а не утечки, а другие удалят только первую запись и утечку. У меня было несколько из них в коде, и valgrind найдет их для вас.

KPexEA 08.10.2008 23:57

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

Brian R. Bondy 08.10.2008 23:58

Я не думаю, что есть утечка памяти, если вы не используете синтаксис []. Но будет вызываться только деструктор для первого элемента массива.

Ferruccio 09.10.2008 00:10

Если ваш компилятор не преобразует автоматически ваш delete в delete [], то определенно есть утечка памяти.

Brian R. Bondy 09.10.2008 00:12

Если вы не используете правильный, удалите результат не определен. Это неверно. Тот факт, что он может частично исправить или сработать, - это просто слепая удача.

Michael Burr 09.10.2008 03:31

Я не думаю, что это вызовет повреждение кучи, он просто увидит это как указатель на один элемент.

Brian R. Bondy 09.10.2008 07:48

См. Пункты 16.12, 16.14 и 38.7 в C++ FAQ: parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.12parashift.com/c++-faq-lite/compiler-dependencies.html#faq-38‌ .7

Michael Burr 09.10.2008 08:10

@KPexEA: Даже если некоторые компиляторы могут исправить ваши ошибки, делать их в первую очередь неправильно :) Всегда используйте delete [] там, где это необходимо.

korona 09.10.2008 12:33

«Если вы не вынуждены использовать C, вы никогда не должны использовать malloc. Всегда используйте new». Почему? В чем здесь выигрыш? Для объектов нам нужна конструкция, но для блоков памяти вы четко документируете два способа сделать ошибки кодирования (более легко отловленный () vs [] в new и менее легко обнаруживаемый несоответствующий массив vs scaler new и delete). Какова мотивация использования new / delete для блоков необработанной памяти?

Ben Supnik 11.02.2010 23:35

типа безопасные средства? Кто-нибудь может уточнить?

user379888 05.05.2011 22:23

«безопасность типов - это степень, в которой язык программирования препятствует или предотвращает ошибки типа» - первая строка википедии

Niroshan 08.06.2011 20:45

Никогда, никогда не используйте new[] и delete[], всегда используйте std::vector.

Puppy 21.12.2011 18:11

@DeadMG: Если кто-то создает массив для использования асинхронной функцией API, не будет ли new[] намного безопаснее, чем std::vector? Если использовать new[], единственный способ, которым указатель станет недействительным, будет через явный delete, в то время как память, выделенная для std::vector, может стать недействительной, когда вектор изменит размер или покинет область видимости. (Обратите внимание, что при использовании new[] необходимо учитывать возможность того, что нельзя будет вызвать delete, если метод async все еще ожидает выполнения; если может потребоваться отказаться от операции async, возможно, придется организовать удаление через Перезвони).

supercat 18.02.2013 20:30

А как насчет многопоточности, например, с OpenMP? Они одинаково безопасны для потоков?

nullgraph 30.01.2015 23:47

Что с realloc() ?, renew нет

Iharob Al Asimi 23.04.2015 15:43

На самом деле никогда не используйте new, но предпочтите его перед malloc, если вам действительно нужно использовать один из них. Оба они требуют ручного управления памятью, сделанного вами. При (почти) всех обстоятельствах у вас есть std::vector и интеллектуальные указатели, которые освобождают память при их разрушении.

Marian Spanik 29.02.2016 21:12

realloc - плохая причина предпочесть malloc, учитывая, что почти все неправильно называют realloc.

Paul Coccoli 20.11.2016 03:36

еще одна плохая причина - каллок

ejectamenta 24.01.2017 16:02

@immibis Этого недостаточно? «это гарантирует, что ваш тип будет иметь конструктор с именем [...] также более безопасен по типу, тогда как malloc вообще не является типобезопасным».

IS4 05.09.2017 01:28

Почему malloc небезопасен по типу?

scottxiao 23.04.2018 13:57

@PaulCoccoli и альтернативный realloc для инициализированных количеств new?

Carpetfizz 22.08.2018 19:48

@Carpetfizz Это зависит от того, что это за инициализированные количества new. Как уже неоднократно говорилось выше, версии realloc, подобной new, не существует.

Paul Coccoli 23.08.2018 18:33

Будет ли это: int* i = new int{ 5 }; лучшим способом инициализации, чем использование круглых скобок?

Dynamic Squid 13.08.2020 20:19

Используйте malloc и freeТолько для выделения памяти, которая будет управляться c-ориентированными библиотеками и API. Используйте new и delete (и варианты []) для всего, что вы контролируете.

Также обратите внимание, что хорошо написанная библиотека C будет скрывать malloc и free внутри, так должен работать программист на C.

Dacav 13.08.2010 22:26

@dmckee у вас есть пример C++ с использованием c-ориентированных библиотек malloc и free?

milesma 31.07.2013 04:44

@Dacav: если функция C примет указатель на объект, который ей нужно будет продолжать использовать после возврата из функции, и у вызывающего не будет возможности узнать, когда объект все еще нужен, это было бы вполне разумно для функции чтобы указать, что указатель должен быть создан с помощью malloc. Аналогично, если такой функции, как strdup, необходимо создать объект и вернуть его вызывающей стороне, вполне разумно указать, что вызывающая сторона должна вызывать free для объекта, когда он больше не нужен. Как такие функции могут избежать раскрытия вызывающей стороне использования malloc / free?

supercat 06.04.2015 20:09

@supercat, есть что-то по своей сути неправильное в том, что функция C принимает указатель на объекты, поскольку C вообще не знает об объектах. В общем, я считаю, что лучший подход - иметь семантические оболочки для выделения / освобождения также и в C. Это может быть все еще приемлемо, но менее гибко, если библиотека C просит вызывающего абонента предварительно выделить и / или освободить память. Если функция C делает это и заявляет о праве собственности на выделенную память, вам неявно требуется выделить ее с помощью malloc.

Dacav 06.04.2015 23:30

@supercat Один из примеров повседневного пакета, который, я уверен, все использовали, - это libgmp. Если вы когда-либо использовали какое-либо шифрование с открытым исходным кодом или программное обеспечение, основанное на таком шифровании (что весьма вероятно), вы, вероятно, использовали арифметическую библиотеку произвольной точности, которая должна увеличиваться и уменьшаться в собственных внутренних данных. Это делается с помощью функции инициализации ... и тогда вы должны задаться вопросом, как вы используете код C, который является libgmp, в C++, без его перекомпиляции в C++? Теперь, имея в виду (компоновщик), подумайте об этом ... зачем любому разумному человеку Когда-либо помещать malloc на C++?

autistic 29.04.2018 18:41

@Sebivor: Стандарт C перегружает термин «объект» для ряда различных, но связанных понятий, которые отличаются от того, как он используется в других контекстах.

supercat 29.04.2018 18:50

Я думаю, что Dacav предлагает, чтобы библиотеки c, реализующие непрозрачные типы, предлагали средство для инициализации непрозрачного хранилища, чтобы детали того, кем эти объекты управляются внутри, были полностью скрыты, и вызывающему абоненту даже не нужно было знать, какая схема управления памятью используется внутри. Но как бы вы ни относились к этому предписанию, есть много мест, где вызывающий должен выполнять распределение (начиная с unix FILEs).

dmckee --- ex-moderator kitten 29.04.2018 18:53

Себивор: Я думаю, возможно, вы имели в виду свой комментарий к @Decav?

supercat 29.04.2018 18:53

[Я имел в виду @Dacav]

supercat 29.04.2018 18:54

@dmckee: Это Dacav сказал, что C вообще не знает об объектах. Ни в базовом языке C, ни в стандартной библиотеке нет широкой концепции функций, которые создают постоянное хранилище или сущности как часть своей работы, кроме тех, чьей целью является создание таких сущностей (например, malloc, fopen и т. д.); все другие функции, которые работают с такими объектами, ожидают, что они были созданы их вызывающей стороной, либо с использованием функций, единственной целью которых было такое создание, либо такими способами, которые вызывающий считает нужными.

supercat 29.04.2018 19:00

@Sebivor: Стандарт C перегружает термин для описания переменных, членов структуры, членов объединения, элементов массива, областей, выделенных malloc, и целей указателя, что приводит к проблемам в таких местах, как, например, 6.5p7, который ограничивает случаи, когда «объект» может получить доступ к своему сохраненному значению.

supercat 29.04.2018 19:04

@supercat Я предполагаю, что стандарт C++ наследует определение стандартов C, поскольку в противном случае он, похоже, не имеет его, и для каждого компилятора C++, который я когда-либо использовал, был совместимый C ABI, который включает такие вещи, как макет структуры и внутреннее представление типов. Кроме того, стандарт C++ фактически говорит об основных типах, таких как массивы символов, как если бы Oни - это объекты.

autistic 29.04.2018 19:12

Подождите, нет, в C++ делает есть определение для «объекта». Здесь ясно и ясно сказано: «Объект - это область хранения».

autistic 29.04.2018 19:15

@Dacav В стандарте C++, раздел Объектная модель C++, мы можем увидеть определение для объект: «Объект - это область хранения». Аналогичное определение есть в стандарте C; char c; как в C, так и в C++, эта переменная обозначает объект. Разница в том, что немного (но не все) объекты в C++ являются полиморфными также (в конце концов, C++ - объектно-ориентированный объект). Не делайте ошибки, полагая, что только объектно-ориентированный код может использовать объекты.

autistic 29.04.2018 19:25

@Sebivor, эти сообщения довольно старые, эта ветка комментариев еще жива? Во всяком случае, я использую объектно-ориентированный дизайн и для программ на C, поэтому полностью с вами согласен.

Dacav 29.04.2018 22:50

@Dacav Правда? Если вы разрабатываете функцию, которая требует определенной формы распределения (и вынуждает остальной мир использовать это распределение по требованию), это технически нарушение принципа инверсии зависимостей, одного из пяти основных принципов объектно-ориентированного проектирования. Не все, что вы можете делать в C++, является объектно-ориентированным, и вы не так много можете сделать с чисто объектно-ориентированными конструкциями. Вы не можете составить логику (последовательность, выбор и итерацию) без (обычно) процедурных или функциональных конструкций. OO - это просто более конкретная форма одного из расширений.

autistic 30.04.2018 07:45

Если у вас есть код C, который вы хотите перенести на C++, вы можете оставить в нем любые вызовы malloc (). Для любого нового кода C++ я бы рекомендовал использовать вместо него new.

Всегда используйте новое в C++. Если вам нужен блок нетипизированной памяти, вы можете напрямую использовать оператор new:

void *p = operator new(size);
   ...
operator delete(p);

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

Greg Rogers 08.10.2008 23:57

Осторожно, семантика должна быть такой: p_var = новый тип (инициализатор); Не размер.

Brian R. Bondy 09.10.2008 00:04

Нет, если вы вызываете оператор new напрямую, тогда требуется количество байтов для выделения в качестве параметра.

Ferruccio 09.10.2008 00:05

Хм не уверен, я никогда не слышал об этом синтаксисе.

Brian R. Bondy 09.10.2008 00:06

@Greg - в любом случае работает одинаково. Мне просто нравится тот факт, что вызов оператора new подчеркивает, что я делаю низкоуровневое нетипизированное распределение.

Ferruccio 09.10.2008 00:06

Противоположность operator new - operator delete. Вызов delete для выражения с типом void* не является четко определенным действием.

CB Bailey 09.10.2008 00:16

Из C++ FQA Lite:

[16.4] Why should I use new instead of trustworthy old malloc()?

FAQ: new/delete call the constructor/destructor; new is type safe, malloc is not; new can be overridden by a class.

FQA: The virtues of new mentioned by the FAQ are not virtues, because constructors, destructors, and operator overloading are garbage (see what happens when you have no garbage collection?), and the type safety issue is really tiny here (normally you have to cast the void* returned by malloc to the right pointer type to assign it to a typed pointer variable, which may be annoying, but far from "unsafe").

Oh, and using trustworthy old malloc makes it possible to use the equally trustworthy & old realloc. Too bad we don't have a shiny new operator renew or something.

Still, new is not bad enough to justify a deviation from the common style used throughout a language, even when the language is C++. In particular, classes with non-trivial constructors will misbehave in fatal ways if you simply malloc the objects. So why not use new throughout the code? People rarely overload operator new, so it probably won't get in your way too much. And if they do overload new, you can always ask them to stop.

Извини, я просто не удержался. :)

Я не могу воспринимать этот комментарий серьезно, поскольку он явно демонстрирует предвзятое отношение автора к C++. C++ - это язык, используемый для создания программного обеспечения, ориентированного на производительность, и сборщик мусора может только навредить его цели. Я не согласен со всем вашим ответом!

Miguel 27.11.2015 00:23

@Miguel Вы пропустили шутку.

Dan Bechard 11.04.2016 20:29

Операторы new и delete могут работать с классами и структурами, тогда как malloc и free работают только с блоками памяти, которые необходимо преобразовать.

Использование new/delete поможет улучшить ваш код, поскольку вам не нужно будет преобразовывать выделенную память в требуемую структуру данных.

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

new обычно не инициализирует память, хотя есть способы сделать это: см. stackoverflow.com/questions/2204176/… для обсуждения этого вопроса.

wjl 30.09.2011 18:54

Короткий ответ: не используйте malloc для C++ без действительно веской причины. malloc имеет ряд недостатков при использовании с C++, для устранения которых был определен new.

Недостатки, исправленные новым для кода C++

  1. malloc не является типобезопасным в каком-либо смысле. В C++ требуется выполнить возврат от void*. Это потенциально создает множество проблем:

    #include <stdlib.h>
    
    struct foo {
      double d[5];
    }; 
    
    int main() {
      foo *f1 = malloc(1); // error, no cast
      foo *f2 = static_cast<foo*>(malloc(sizeof(foo)));
      foo *f3 = static_cast<foo*>(malloc(1)); // No error, bad
    }
    
  2. Хотя все еще хуже. Если рассматриваемый тип - POD (простые старые данные), тогда вы можете разумно использовать malloc для выделения для него памяти, как это делает f2 в первом примере.

    Однако это не так очевидно, если тип - POD. Тот факт, что данный тип может измениться с POD на не-POD без результирующей ошибки компилятора и потенциально очень трудных для отладки проблем, является важным фактором. Например, если кто-то (возможно, другой программист, во время обслуживания, намного позже, внесет изменение, из-за которого foo больше не будет POD, то во время компиляции не появится очевидная ошибка, как вы надеетесь, например:

    struct foo {
      double d[5];
      virtual ~foo() { }
    };
    

    приведет к тому, что malloc из f2 также станет плохим, без какой-либо очевидной диагностики. Пример здесь тривиален, но можно случайно ввести не-POD-качество намного дальше (например, в базовый класс, добавив не-POD-член). Если у вас есть C++ 11 / boost, вы можете использовать is_pod, чтобы проверить правильность этого предположения и выдать ошибку, если это не так:

    #include <type_traits>
    #include <stdlib.h>
    
    foo *safe_foo_malloc() {
      static_assert(std::is_pod<foo>::value, "foo must be POD");
      return static_cast<foo*>(malloc(sizeof(foo)));
    }
    

    Хотя boost - это невозможно определить, является ли тип POD без C++ 11 или некоторых других расширений компилятора.

  3. malloc возвращает NULL в случае сбоя выделения. new выбрасывает std::bad_alloc. Поведение при последующем использовании указателя NULL не определено. Исключение имеет чистую семантику, когда оно выбрасывается из источника ошибки. Добавление malloc к соответствующему тесту при каждом вызове кажется утомительным и подверженным ошибкам. (Вам нужно только один раз забыть, чтобы отменить всю эту хорошую работу). Исключению можно разрешить распространиться на уровень, на котором вызывающий может разумно его обработать, тогда как NULL гораздо сложнее передать обратно осмысленно. Мы могли бы расширить нашу функцию safe_foo_malloc, чтобы генерировать исключение, или выйти из программы, или вызвать некоторый обработчик:

    #include <type_traits>
    #include <stdlib.h>
    
    void my_malloc_failed_handler();
    
    foo *safe_foo_malloc() {
      static_assert(std::is_pod<foo>::value, "foo must be POD");
      foo *mem = static_cast<foo*>(malloc(sizeof(foo)));
      if (!mem) {
         my_malloc_failed_handler();
         // or throw ...
      }
      return mem;
    }
    
  4. По сути, malloc - это функция C, а new - функция C++. В результате malloc не очень хорошо работает с конструкторами, он смотрит только на выделение части байтов. Мы могли бы расширить наш safe_foo_malloc, чтобы использовать размещение new:

    #include <stdlib.h>
    #include <new>
    
    void my_malloc_failed_handler();
    
    foo *safe_foo_malloc() {
      void *mem = malloc(sizeof(foo));
      if (!mem) {
         my_malloc_failed_handler();
         // or throw ...
      }
      return new (mem)foo();
    }
    
  5. Наша функция safe_foo_malloc не очень универсальна - в идеале нам нужно что-то, что может обрабатывать любой тип, а не только foo. Мы можем добиться этого с помощью шаблонов и вариативных шаблонов для конструкторов, отличных от стандартных:

    #include <functional>
    #include <new>
    #include <stdlib.h>
    
    void my_malloc_failed_handler();
    
    template <typename T>
    struct alloc {
      template <typename ...Args>
      static T *safe_malloc(Args&&... args) {
        void *mem = malloc(sizeof(T));
        if (!mem) {
           my_malloc_failed_handler();
           // or throw ...
        }
        return new (mem)T(std::forward(args)...);
      }
    };
    

    Теперь, исправляя все проблемы, которые мы выявили до сих пор, мы практически заново изобрели оператор new по умолчанию. Если вы собираетесь использовать malloc и размещение new, тогда вы можете просто использовать new для начала!

Жаль, что в C++ struct и class означают в основном одно и то же; Интересно, возникли бы какие-либо проблемы с тем, чтобы struct был зарезервирован для POD и, возможно, все типы class считались не-POD. Любые типы, определенные кодом, предшествующим изобретению C++, обязательно будут POD, поэтому я не думаю, что обратная совместимость будет здесь проблемой. Есть ли преимущества в том, что типы, не относящиеся к POD, объявлены как struct, а не class?

supercat 18.02.2013 20:15

@supercat Немного поздно, но, как выяснилось, заставить struct и class делать почти одно и то же было замечательным дизайнерским решением, которое теперь позволяет использовать изящную функцию под названием "метаклассы" (от Herb).

Rakete1111 13.10.2018 22:42

@ Rakete1111: На первый взгляд это предложение выглядит так, как будто оно предварительно обрабатывает версию языка, в которой используются ключевые слова с префиксом доллара, такие как $class. Однако я не уверен, какое отношение это имеет к тому, что class и struct являются синонимами.

supercat 13.10.2018 22:50

@supercat Система типов была бы более раздвоенной. Если class и struct означают одно и то же, вы можете выполнять произвольные преобразования на них ($class), не беспокоясь о том, что class превратится в struct и наоборот.

Rakete1111 13.10.2018 22:54

@ Rakete1111: Если определенные виды операций и преобразований безопасны для одних типов, но не для других, то наличие типа, непосредственно идентифицирующего это, и наличие компилятора, отклоняющего небезопасные операции и преобразования, было бы лучше, чем изменение метакласса, который использовался в способы, которые подходят только для PODS, автоматически меняются на не-PODS.

supercat 13.10.2018 22:58

@supercat Я не понял, извините. Я имел в виду что-то вроде template<class T> struct X { T t; };, действительного только тогда, когда T - это под. То же самое можно применить к метаклассам, когда вы выполняете преобразование класса, которое может изменить его член таким образом, чтобы класс стал подом; либо случайно, либо нет.

Rakete1111 13.10.2018 23:02

@ Rakete1111: Требования к тому, чтобы что-то было PODS, немного строже, чем требования к присутствию в struct; Самым большим требованием должна быть стандартная планировка. Понятие struct в C было связано с представлением о том, что каждый T занимает диапазон последовательных байтов sizeof (T), а структура представляет собой конкатенацию таких последовательностей байтов с дополнительным заполнением, в то время как понятие «размер» бессмысленно для типов классов.

supercat 14.10.2018 00:02

Есть одно большое различие между malloc и new. malloc выделяет память. Это нормально для C, потому что в C кусок памяти является объектом.

В C++, если вы не имеете дело с типами POD (которые похожи на типы C), вы должны вызвать конструктор в области памяти, чтобы действительно иметь там объект. Типы, не относящиеся к POD, очень распространены в C++, поскольку многие функции C++ автоматически делают объект не-POD.

new выделяет память. и создает объект в этой области памяти. Для типов, не относящихся к POD, это означает вызов конструктора.

Если вы сделаете что-то вроде этого:

non_pod_type* p = (non_pod_type*) malloc(sizeof *p);

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

Если, с другой стороны, вы делаете:

non_pod_type* p = new non_pod_type();

Вы получаете указатель, который всегда действителен, потому что new создал объект.

Даже для типов POD между ними есть существенная разница:

pod_type* p = (pod_type*) malloc(sizeof *p);
std::cout << p->foo;

Этот фрагмент кода будет печатать неопределенное значение, потому что объекты POD, созданные malloc, не инициализируются.

С new вы можете указать конструктор для вызова и, таким образом, получить четко определенное значение.

pod_type* p = new pod_type();
std::cout << p->foo; // prints 0

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

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

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

По этим причинам в коде C++ следует использовать new, а не malloc. Но даже в этом случае вам не следует использовать new «открыто», потому что он привлекает ресурсы, которые вам нужно выпустить позже. Когда вы используете new, вы должны немедленно передать его результат в класс управления ресурсами:

std::unique_ptr<T> p = std::unique_ptr<T>(new T()); // this won't leak

malloc () используется для динамического выделения памяти в C в то время как та же работа выполняется new () в C++. Таким образом, вы не можете смешивать соглашения о кодировании двух языков. Было бы хорошо, если бы вы спросили разницу между calloc и malloc ()

Вы может (но почти всегда не должны) использовать malloc в C++.

interjay 26.07.2012 17:06

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

thecoshman 11.10.2012 14:55

В следующем сценарии мы не можем использовать new, поскольку он вызывает конструктор.

class  B  {
private:
    B *ptr;
    int x;
public:
    B(int n)  {
        cout<<"B: ctr"<<endl;
        //ptr = new B;  //keep calling ctr, result is segmentation fault
        ptr = (B *)malloc(sizeof(B));
        x = n;
        ptr->x = n + 10;
    }
    ~B()  {
        //delete ptr;
        free(ptr);
        cout<<"B: dtr"<<endl;
    }
};

Если вы работаете с данными, которые не нуждаются в построении / уничтожении и требуют перераспределения (например, большой массив целых чисел), то я считаю, что malloc / free - хороший выбор, поскольку он дает вам перераспределение, что намного быстрее, чем new-memcpy -delete (это на моем компьютере с Linux, но я предполагаю, что это может зависеть от платформы). Если вы работаете с объектами C++, которые не являются POD и требуют построения / уничтожения, вы должны использовать операторы new и delete.

В любом случае, я не понимаю, почему вы не должны использовать оба (при условии, что вы освобождаете свою malloced память и удаляете объекты, выделенные с помощью new), если можете воспользоваться преимуществом повышения скорости (иногда значительного, если вы повторно блокируете большие массивы POD), который может дать вам realloc.

Если вам это не нужно, вы должны придерживаться new / delete в C++.

Есть несколько вещей, которые new делает, но не malloc:

  1. new создает объект, вызывая конструктор этого объекта.
  2. new не требует приведения типа выделенной памяти.
  3. Для этого не требуется выделять объем памяти, а требуется несколько объекты для строительства.

Итак, если вы используете malloc, вам нужно делать указанные выше вещи явно, что не всегда практично. Кроме того, new может быть перегружен, а malloc - нет.

Если вы используете C++, попробуйте использовать new / delete вместо malloc / calloc, поскольку они являются операторами. Для malloc / calloc вам нужно включить другой заголовок. Не смешивайте два разных языка в одном коде. Их работа во всех отношениях схожа, оба динамически распределяют память из сегмента кучи в хеш-таблице.

новый против malloc ()

1) new - это оператор, а malloc() - это функция.

2) new вызывает конструкторы, а malloc() - нет.

3) new возвращает точный тип данных, а malloc() возвращает пустота *.

4) new никогда не возвращает НУЛЕВОЙ (выдает при сбое), в то время как malloc() возвращает NULL

5) Перераспределение памяти не обрабатывается new, в то время как malloc() может

Привет! Что касается пункта 4), можно дать команду new возвращать NULL в случае ошибки. char* ptr = new (std::nothrow) char [323232];

Singh 07.10.2016 11:54

6) new создает из аргументов конструктора, а malloc использует размер.

Evan Moran 16.10.2016 18:03

есть еще функция new

Ma Ming 18.10.2017 12:06

Если бы вы были так склонны к C, как к перераспределить, я бы надеялся, что вы использовали бы realloc, а не malloc, и начнете с вашей переменной-указателя, инициализированной на NULL. С другой стороны, если вам нужен кусок памяти изменяемый размер в C++, я бы предложил std::vector, а не realloc ... То или файл.

autistic 29.04.2018 19:35

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

Например.

struct test_s {
    int some_strange_name = 1;
    int &easy = some_strange_name;
}

Таким образом, new struct test_s вернет инициализированную структуру с рабочей ссылкой, в то время как версия с измененной локализацией не имеет значений по умолчанию, а внутренние ссылки не инициализируются.

Редкий случай использования malloc / free вместо new / delete - это когда вы выделяете, а затем перераспределяете (простые типы модулей, а не объекты) с помощью realloc, поскольку в C++ нет аналогичной функции для realloc (хотя это можно сделать с помощью больше подход C++).

Чтобы ответить на ваш вопрос, вы должны знать разница между malloc и new. Отличие простое:

mallocвыделяет память, а newвыделяет память и вызывает конструктор объекта, для которого вы выделяете память.

Итак, если вы не ограничены C, вам никогда не следует использовать malloc, особенно при работе с объектами C++. Это был бы рецепт нарушения вашей программы.

Также разница между free и delete такая же. Разница в том, что delete вызовет деструктор вашего объекта в дополнение к освобождению памяти.

Динамическое распределение требуется только тогда, когда время жизни объекта должно отличаться от области, в которой он создается (это также справедливо для уменьшения области действия), и у вас есть конкретная причина, по которой его сохранение по значению не Работа.

Например:

 std::vector<int> *createVector(); // Bad
 std::vector<int> createVector();  // Good

 auto v = new std::vector<int>(); // Bad
 auto result = calculate(/*optional output = */ v);
 auto v = std::vector<int>(); // Good
 auto result = calculate(/*optional output = */ &v);

Начиная с C++ 11, у нас есть std::unique_ptr для работы с выделенной памятью, которая содержит владение выделенной памятью. std::shared_ptr был создан для случаев, когда вам нужно разделить владение. (вам понадобится меньше, чем вы ожидаете от хорошей программы)

Создание экземпляра становится действительно простым:

auto instance = std::make_unique<Class>(/*args*/); // C++14
auto instance = std::unique_ptr<Class>(new Class(/*args*/)); // C++11
auto instance = std::make_unique<Class[]>(42); // C++14
auto instance = std::unique_ptr<Class[]>(new Class[](42)); // C++11

C++ 17 также добавляет std::optional, который может помешать вам требовать выделения памяти.

auto optInstance = std::optional<Class>{};
if (condition)
    optInstance = Class{};

Как только «экземпляр» выходит из области видимости, память очищается. Передать право собственности также просто:

 auto vector = std::vector<std::unique_ptr<Interface>>{};
 auto instance = std::make_unique<Class>();
 vector.push_back(std::move(instance)); // std::move -> transfer (most of the time)

Итак, когда вам все еще нужен new? Практически никогда с C++ 11. В большинстве случаев вы используете std::make_unique, пока не дойдете до точки, в которой вы попадете в API, который передает право собственности через необработанные указатели.

 auto instance = std::make_unique<Class>();
 legacyFunction(instance.release()); // Ownership being transferred

 auto instance = std::unique_ptr<Class>{legacyFunction()}; // Ownership being captured in unique_ptr

В C++ 98/03 вам придется вручную управлять памятью. В этом случае попробуйте выполнить обновление до более новой версии стандарта. Если вы застряли:

 auto instance = new Class(); // Allocate memory
 delete instance;             // Deallocate
 auto instances = new Class[42](); // Allocate memory
 delete[] instances;               // Deallocate

Убедитесь, что вы правильно отслеживаете право собственности, чтобы не было утечек памяти! Семантика перемещения тоже пока не работает.

Итак, когда нам нужен malloc в C++? Единственная веская причина - выделить память и инициализировать ее позже путем размещения new.

 auto instanceBlob = std::malloc(sizeof(Class)); // Allocate memory
 auto instance = new(instanceBlob)Class{}; // Initialize via constructor
 instance.~Class(); // Destroy via destructor
 std::free(instanceBlob); // Deallocate the memory

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

Наконец, у нас все еще есть слон в комнате: C. Если вам нужно работать с C-библиотекой, где память выделяется в коде C++ и освобождается в коде C (или наоборот), вы вынуждены использовать malloc / free.

Если вы в этом случае, забудьте о виртуальных функциях, функциях-членах, классах ... Разрешены только структуры с POD.

Некоторые исключения из правил:

  • Вы пишете стандартную библиотеку с расширенными структурами данных, где подходит malloc
  • Вам нужно выделить большой объем памяти (в памяти копия файла размером 10 ГБ?)
  • У вас есть инструменты, которые не позволяют использовать определенные конструкции.
  • Вам нужно хранить неполный тип

Другие вопросы по теме