malloc موروثة من لغة C، وnew عامل أصيل بـ C++ — يبدوان متشابهين (كلاهما يحجز ذاكرة على الكومة) لكن الفرق بينهما جوهري وخطير لو خُلط بينهما.
malloc — تخصيص ذاكرة خام
malloc (من <cstdlib>) تحجز كتلة بايتات خام فقط، بلا أي معرفة بنوع
البيانات ولا استدعاء لأي باني:
#include <cstdlib>
// malloc تُرجع void* — يجب تحويلها يدويًا للنوع المطلوب
int* p = (int*)malloc(sizeof(int));
*p = 42;
free(p); // تحرير — لا يستدعي أي هادم لأنه لا يوجد كائن حقيقي أصلًا
new — تخصيص واستدعاء باني معًا
new عامل لغوي أصيل بـ C++: يحجز الذاكرة ويستدعي باني النوع تلقائيًا،
وآمن بالأنواع (لا يحتاج تحويلًا يدويًا):
int* p = new int(42); // يحجز ويهيّئ بالقيمة 42 مباشرة، بلا تحويل نوع
class Point {
int x, y;
public:
Point(int x, int y) : x(x), y(y) {
std::cout << "باني Point استُدعي\n";
}
};
Point* pt = new Point(3, 4); // ✅ يستدعي الباني فعليًا
delete pt; // يستدعي الهادم أولًا، ثم يحرّر الذاكرة
مع malloc، لو حاولت نفس الشيء مع صنف Point، الباني لن يُستدعى إطلاقًا
— الذاكرة تُحجز خامة فقط، والكائن يبقى بحالة غير مهيَّأة.
جدول المقارنة
| الجانب | malloc / free | new / delete |
|---|---|---|
| المصدر | مكتبة C (<cstdlib>) | عامل لغوي أصيل بـ C++ |
| استدعاء الباني/الهادم | ❌ لا يحدث إطلاقًا | ✅ تلقائي دائمًا |
| نوع القيمة المُرجَعة | void* (يحتاج تحويل يدوي) | نوع صحيح مباشرة (آمن بالأنواع) |
| فشل التخصيص | يُرجع nullptr | يرمي استثناء std::bad_alloc |
| يصلح لكائنات الأصناف؟ | ❌ لا | ✅ نعم |
القاعدة الذهبية: لا تخلط بينهما أبدًا
int* a = (int*)malloc(sizeof(int));
delete a; // ❌ سلوك غير معرَّف — malloc وdelete نظامان منفصلان تمامًا
int* b = new int(5);
free(b); // ❌ سلوك غير معرَّف أيضًا، بنفس السبب
كل ذاكرة حُجزت بـ malloc يجب تحريرها بـ free، وكل ذاكرة حُجزت بـ new يجب
تحريرها بـ delete (أو أفضل: عبر مؤشّر ذكي لا
يحتاج تحريرًا يدويًا إطلاقًا).
الخلاصة العملية
بكود C++ حديث، لا داعٍ لاستخدام malloc نهائيًا إلا في سياقات توافق خاصة مع
كود C قديم. استخدم new عند الحاجة الفعلية لتحكم يدوي، أو الأفضل: استخدم
المؤشّرات الذكية (unique_ptr/shared_ptr)
التي تُدير التحرير تلقائيًا عبر مبدأ RAII.