У яких випадках я використовую malloc та / або new?


479

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

Якщо ви експерт з питань C ++, будь ласка, повідомте мене про будь-які основні правила чи умови, яких ви дотримуєтесь у цьому плані.


33
Я просто хотів би додати нагадування про те, що ви не можете змішати два стилі - тобто ви не можете використовувати новий для створення об'єкта, а потім викликати на ньому free (), а також не намагатися видалити блок, виділений malloc (). Мабуть, очевидно, що це можна сказати, але тим не менше ...
nsayer

32
Хороші відповіді, все, що я повинен додати (що я не бачив) - це те, що нове / видалене викликає конструктор / деструктор для вас, malloc / free не робить. Просто різницю, яку варто згадати.
Білл К

З сучасним C ++ я все ще намагаюся знайти причину для використання будь-якого.
Ралі

Або не використовуйте жодне і перейдіть до std: shared_ptr <T>. Тоді зовсім не потрібно видаляти.
Вінсент

Відповіді:


387

Якщо ви не змушені використовувати 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

2
Що стосується виклику видалити foo, коли ви повинні викликати delete [] foo, деякі компілятори виправлять це автоматично для вас, а не протікають, а інші видалять лише перший запис та витік. У мене було декілька таких у деякому коді, і valgrind знайде їх для вас.
KPexEA

30
Якщо ви не використовуєте правильне видалення, результат не визначений . Це неправильно. Той факт, що він може отримати частину речі правильно чи іноді працювати - це просто сліпа удача.
Майкл Берр

8
@KPexEA: Навіть якщо деякі компілятори можуть виправити ваші помилки, все-таки неправильно робити їх в першу чергу :) Завжди використовуйте delete [], де це доречно.
корона

62
"Якщо ви не змушені використовувати C, ви ніколи не використовуєте malloc. Завжди використовуйте новий." Чому? Яка тут виграш? Для об'єктів нам потрібна побудова, але для блоків пам’яті ви чітко документуєте два способи помилки кодування (тим, що легше потрапляє () проти [] у новий і менш легко спійманий невідповідний масив проти скалера new та delete). Яка мотивація використання нового / видалення для блоків необробленої пам'яті?
Бен Супник

3
@DeadMG: Якщо один створює масив для використання асинхронною функцією API, це не new[]буде набагато безпечніше, ніж std::vector? Якщо використовується new[], єдиний спосіб, коли вказівник став би недійсним, був би через явний delete, тоді як пам'ять, виділена для символу, std::vectorможе бути недійсною, коли вектор змінюється за розміром або залишає область. (Зверніть увагу, що при використанні new[]одного потрібно було б передбачити можливість того, що ви не зможете зателефонувати, deleteякщо метод асинхронізації все ще очікується; якщо може знадобитися відмовитися від операції асинхронізації, можливо, доведеться домовитись про видалення за допомогою зворотного виклику) .
supercat

144

Коротка відповідь: не використовуйте 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до відсутності ПОД, тоді очевидна помилка не з’явиться під час компіляції, як ви сподівалися, наприклад:

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

    зробить mallocз f2також стати погано, без яких - або очевидних діагностики. Приклад тут тривіальний, але можна випадково ввести не-PODness набагато далі (наприклад, в базовий клас, додавши член, який не є 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для початку!


27
Це занадто погано, C ++ зроблено structі classозначає в основному те саме; Цікаво, чи були б якісь проблеми з тим, щоб structбути зарезервованими для ПОД і, можливо, всі classтипи вважатимуться такими, що не є ПОД. Будь-які типи, визначені кодом, який передував винайдженню C ++, обов'язково мали би бути POD, тому я не думаю, що зворотна сумісність буде проблемою. Чи існує перевага, мають тип не-стручків оголошується , як structзамість class?
supercat

1
@supercat Трохи запізнився, але, як виявляється, зробити structта classзробити майже те саме було чудовим дизайнерським рішенням, яке тепер дозволяє чітку функцію під назвою "метакласи" (від Herb) .
Rakete1111

@ Rakete1111: На перший погляд, ця пропозиція виглядає так, що вона попередньо обробляє версію мови, яка використовує ключові слова з попередньо встановленими доларами $class. Я не впевнений, що це стосується classі structє синонімами.
supercat

@supercat Система типів би роздвоєна більше. Маючи classта маючи на structувазі ефективно одне й те саме, ви можете робити довільні перетворення на них ( $class), не переживаючи про введення classа structта навпаки.
Rakete1111

@ Rakete1111: Якщо певні операції та перетворення є безпечними для деяких типів, але не для інших, то тип, який безпосередньо ідентифікує це, і компілятор відхиляє небезпечні операції та перетворення, здається кращим, ніж зміна метакласу, який використовувався в способи, які підходять лише для PODS, мовчки змінюються на не-PODS.
supercat

53

Від C ++ FQA Lite :

[16.4] Чому я повинен використовувати новий замість надійного старого malloc ()?

FAQ: новий / видалити виклик конструктора / деструктора; new - безпечний тип, malloc - ні; новий може бути замінений класом.

FQA: Чесноти, про які йдеться у FAQ, не є чеснотами, оскільки конструктори, деструктори та перевантаження оператора - сміття (дивіться, що відбувається, коли у вас немає сміття?), А питання безпеки типу тут справді крихітний (зазвичай у вас є передати порожнечу *, повернуту malloc, на правий тип вказівника, щоб призначити її введеній змінній вказівника, яка може бути прикрою, але далеко не "небезпечною").

О, а використання надійного старого malloc дає змогу використовувати однаково надійний та старий realloc. Шкода, що у нас немає блискучого нового оновлення оператора чи чогось іншого.

І все-таки нове не є достатньо поганим, щоб виправдати відхилення від загального стилю, що використовується в мові, навіть коли мова є C ++. Зокрема, класи з нетривіальними конструкторами будуть погано поводитись фатально, якщо ви просто зловживаєте об'єктами. То чому б не використати новий у всьому коді? Люди рідко перевантажують нового оператора, тому він, мабуть, не заважає вам занадто сильно. І якщо вони перевантажують нові, ви завжди можете попросити їх зупинитися.

Вибачте, я просто не втримався. :)



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

1
@Miguel Ви пропустили жарт.
Ден Бешард

50

Завжди використовуйте нове в C ++. Якщо вам потрібен блок нетипізованої пам'яті, ви можете використовувати оператор new безпосередньо:

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

3
Що цікаво, я завжди просто виділяв масив неподписаних знаків, коли мені потрібен такий необроблений буфер даних.
Грег Роджерс

Обережна семантика повинна бути такою: p_var = новий тип (ініціалізатор); Не розмір.
Брайан Р. Бонді

11
Якщо ви не зателефонуєте оператору new безпосередньо, то в якості параметра потрібно виділити кількість байтів.
Ферруччо

1
Hrm не впевнений, я ніколи не чув про цей синтаксис.
Брайан Р. Бонді

9
Навпаки operator newє operator delete. Не чітко визначена дія викликати deleteвираз із типом void*.
CB Bailey

33

Використовуйте mallocі лише для розподілу пам'яті, якою керуватимуть c-центричні бібліотеки та API. Використовуйте та (і варіанти) для всього, що ви контролюєте.free newdelete[]


10
Також зауважте, що добре написана C-бібліотека приховає внутрішню програму та вільну програму, саме так повинен працювати програміст C
Дакав

@dmckee Чи є у вас приклад C ++ з використанням c -центричних бібліотек malloc та free?
milesma

1
@Dacav: Якщо функція C прийме вказівник на об’єкт, який йому потрібно буде продовжувати використовувати після повернення функції, і абонент не зможе дізнатися, коли об'єкт все ще потрібен, це було б цілком розумно для функції щоб вказати, що вказівник повинен бути створений за допомогою malloc. Так само, якщо така функція strdupповинна створити об'єкт і повернути його абоненту, цілком розумно вказати, що абонент повинен викликати freeоб'єкт, коли він більше не потрібен. Як такі функції могли уникнути піддавати користувачеві malloc / free абоненту?
supercat

@supercat, щось невід'ємне в тому, що функція C приймає покажчик на об'єкти, оскільки C взагалі не знає про об'єкти. Загалом, я вважаю, що найкращим підходом є створення семантичних обгортків навколо розподілу / дислокації також у C. Це все ще може бути прийнятним, але менш гнучким, якщо бібліотека С просить абонента попередньо виділити та / або розібрати пам'ять. Якщо функція C робить це і вимагає право власності на виділену пам'ять, вам неявно потрібно виділити її з malloc.
Дакав

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

31

новий vs malloc ()

1) newє оператором , а malloc()є функцією .

2) newвикликає конструктори , поки malloc()не робить.

3) newповертає точний тип даних , тоді як malloc()повертає недійсні * .

4) newніколи не повертає NULL (викине з ладу), тоді як malloc()повертає NULL

5) Перерозподіл пам'яті, не обробляється newпоки malloc()може


6
Привіт, для пункту 4) нове може бути доручено повернути NULL при відмові. char* ptr = new (std::nothrow) char [323232];
Сінгх

1
6) новий створює з аргументів конструктора, в той час як malloc використовує розмір.
Еван Моран

є також newфункція
Ma Ming

Якщо ви були настільки схильні в C, щоб перерозподілити їх , я би сподівався, що ви скористаєтесь, reallocа не mallocпочнете із своєї ініціалізованої змінної вказівника NULL. Якщо ви хочете змінюваний шматок пам'яті в C ++, з іншого боку, я б припустити , std::vectorна відміну від realloc... Це або файлу.
аутист

19

Щоб відповісти на ваше запитання, ви повинні знати різницю між mallocіnew . Різниця проста:

malloc виділяє пам'ять , при цьому new виділяє пам'ять І викликає конструктор об'єкта, для якого ви виділяєте пам'ять.

Отже, якщо ви не обмежені на C, ви ніколи не повинні використовувати malloc, особливо при роботі з об'єктами C ++. Це був би рецепт порушення вашої програми.

Також різниця між freeі deleteзовсім однакова. Різниця полягає в тому, що deleteвикличе деструктор вашого об'єкта, крім звільнення пам'яті.


13

Є одна велика різниця між 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

7

Динамічний розподіл потрібен лише тоді, коли час життя об'єкта повинен відрізнятися від обсягу, який він створює (Це справедливо і для того, щоб зменшити обсяг як більший), і у вас є конкретна причина, коли зберігання його за значенням не означає робота.

Наприклад:

 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::make_unique<Class>(new Class(/*args*/)); // C++11
auto instance = std::make_unique<Class[]>(42); // C++14
auto instance = std::make_unique<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 ++? Єдиною вагомою причиною було б виділити пам'ять та ініціалізувати її пізніше, розміщуючи нову.

 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

Незважаючи на те, що вищезазначене є дійсним, це можна зробити і через нового оператора. std::vectorє хорошим прикладом для цього.

Нарешті, у нас ще є слон в кімнаті: C. Якщо вам доведеться працювати з бібліотекою С, де пам'ять отримується в коді C ++ і звільняється в коді С (або навпаки), ви змушені використовувати malloc / free.

Якщо ви в цьому випадку, забудьте про віртуальні функції, функції членів, класи ... Дозволені лише структури з POD-адресами в ньому.

Деякі винятки з правил:

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

6

Є кілька речей, що newне mallocробить:

  1. new будує об'єкт, викликаючи конструктор цього об'єкта
  2. new не вимагає набору даних виділеної пам'яті.
  3. Для цього не потрібно виділяти об'єм пам'яті, швидше потрібно побудувати ряд об'єктів.

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


5

Якщо ви працюєте з даними, які не потребують побудови / знищення та потребують перерозподілу (наприклад, великий масив ints), то я вважаю, що malloc / free є хорошим вибором, оскільки він дає вам reallock, що швидше, ніж new-memcpy -delete (він знаходиться в моєму вікні Linux, але я думаю, це може залежати від платформи). Якщо ви працюєте з об'єктами C ++, які не є POD і не потребують побудови / знищення, тоді ви повинні використовувати нові та видалити оператори.

У будь-якому випадку, я не бачу, чому ви не повинні використовувати обидва (за умови звільнення пам’яті, що виділяється, та видалення об'єктів, виділених новими), якщо ви можете скористатися збільшенням швидкості (іноді важливою, якщо ви перерозподіляєте великі масиви від POD), який може вам надати realloc.

Якщо вам це не потрібно, вам слід дотримуватися нового / видалити в C ++.


3

Якщо у вас є код C, який ви хочете передати на C ++, ви можете залишити в ньому будь-які дзвінки malloc (). Для будь-якого нового коду C ++ я рекомендую замість цього використовувати новий.


3

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


2

new буде ініціалізувати значення за замовчуванням структури та правильно пов'язувати посилання в ньому до себе.

Напр

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

Таким чином new struct test_s, поверне ініціалізовану структуру з робочим посиланням, тоді як у malloc'ed версії немає значень за замовчуванням, а посилання інтерна не ініціалізуються.


1

З нижчої точки зору, новий ініціалізує всю пам'ять перед тим, як віддавати пам'ять, тоді як malloc збереже оригінальний вміст пам'яті.


4
new взагалі не ініціалізує пам'ять, хоча є способи зробити це: див. stackoverflow.com/questions/2204176/… для однієї дискусії про неї.
wjl

0

У наступному сценарії ми не можемо використовувати новий, оскільки він викликає конструктор.

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;
    }
};

0

Ці newта deleteоператори можуть працювати на класи і структури, в той час , mallocі freeпрацюють тільки з блоками пам'яті , які повинні бути литий.

Використання new/deleteдопоможе покращити ваш код, оскільки вам не потрібно буде передавати виділену пам’ять необхідній структурі даних.


0

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


-4

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


2
Ви можете (але майже завжди не повинні) використовувати mallocв C ++.
interjay

1
Ви також пропустили першочергову точку, що вам слід прагнути уникати динамічного розподілу пам’яті, якщо це не робити через розумні покажчики. Ви просто налаштовуєте себе на біль іншим мудрецям
thecoshman
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.