Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

الذاكرة الديناميكية (new/delete)

جزء من قسم Object Oriented Programming في رحلة C++ على Coddy — الدرس 14 من 104.

الآن بعد أن فهمت المؤشرات والمراجع، لنستخدمها في تخصيص الذاكرة الديناميكي. يسمح لك عاملا new و delete بإنشاء وتدمير الكائنات في الذاكرة المكدسة (heap) أثناء وقت التشغيل.

استخدم new لتخصيص الذاكرة والحصول على مؤشر إليها:

int* num = new int;        // تخصيص عدد صحيح واحد
*num = 42;                 // تعيين قيمة من خلال المؤشر

Player* player = new Player("Hero");  // تخصيص كائن

كل new يجب أن يكون له delete مطابق لتحرير الذاكرة:

delete num;      // تحرير كائن واحد
delete player;   // يستدعي المدمر (destructor)، ثم يحرر الذاكرة

بالنسبة للمصفوفات، استخدم new[] و delete[]:

int* scores = new int[5];    // تخصيص مصفوفة من 5 أعداد صحيحة
scores[0] = 100;

delete[] scores;             // تحرير المصفوفة - لاحظ الأقواس!

أخطاء شائعة يجب تجنبها:

// تسرب الذاكرة - نسيان الحذف (delete)
int* ptr = new int(10);
ptr = new int(20);    // فقدان الوصول إلى التخصيص الأول!

// مؤشر معلق - الاستخدام بعد الحذف
delete ptr;
*ptr = 5;             // سلوك غير محدد!

// عدم تطابق الحذف (delete)
int* arr = new int[10];
delete arr;           // خطأ! يجب أن يكون delete[]

بعد الحذف، قم بتعيين المؤشرات إلى nullptr لتجنب إعادة الاستخدام العرضي. تعد إدارة الذاكرة اليدوية عرضة للأخطاء، ولهذا السبب تفضل لغة ++C الحديثة المؤشرات الذكية، والتي سنستكشفها لاحقاً.

challenge icon

التحدي

سهل

لنقم ببناء نظام بسيط لتخزين الرسائل يوضح تخصيص الذاكرة الديناميكي باستخدام new و delete.

ستقوم بإنشاء ملفين لتنظيم الكود الخاص بك:

  • MessageBox.h: قم بتعريف فئة MessageBox تدير مصفوفة من الرسائل ديناميكيًا. يجب أن تحتوي الفئة على:
    • مؤشر خاص (private pointer) لمصفوفة من السلاسل النصية المخصصة ديناميكيًا
    • متغير صحيح خاص يتتبع العدد الحالي للرسائل
    • متغير صحيح خاص يخزن السعة القصوى
    • منشئ (constructor) يأخذ السعة ويخصص المصفوفة باستخدام new[]
    • مدمر (destructor) يحرر الذاكرة بشكل صحيح باستخدام delete[] ويطبع "MessageBox destroyed"
    • دالة addMessage(string msg) تضيف رسالة إذا كانت هناك مساحة، وتعيد true عند النجاح أو false إذا كانت ممتلئة
    • دالة printAll() تطبع كل رسالة مخزنة في سطر منفصل
  • main.cpp: اقرأ قيمة السعة وعدد الرسائل من المدخلات. ثم اقرأ هذا العدد من السلاسل النصية للرسائل. قم بإنشاء MessageBox على الـ heap باستخدام new، وأضف جميع الرسائل إليه، واستدعِ printAll()، ثم قم بحذف MessageBox بشكل صحيح لتحرير الذاكرة.

سيكون تنسيق المدخلات كالتالي:

  • السطر الأول: السعة (عدد صحيح)
  • السطر الثاني: عدد الرسائل المراد إضافتها (عدد صحيح)
  • الأسطر التالية: رسالة واحدة في كل سطر

تذكر: كل new تحتاج إلى delete مطابقة، وكل new[] تحتاج إلى delete[] مطابقة. بعد الحذف، من الممارسات الجيدة تعيين المؤشرات إلى nullptr.

قم بتضمين ملف الترويسة (header file) في main.cpp باستخدام #include "MessageBox.h".

ورقة مرجعية

استخدم new لتخصيص الذاكرة ديناميكيًا على الـ heap والحصول على مؤشر (pointer) إليها:

int* num = new int;        // Allocate single integer
*num = 42;                 // Assign value through pointer

Player* player = new Player("Hero");  // Allocate object

كل عملية new يجب أن يقابلها delete مطابقة لتحرير الذاكرة:

delete num;      // Free single object
delete player;   // Calls destructor, then frees memory

بالنسبة للمصفوفات، استخدم new[] و delete[]:

int* scores = new int[5];    // Allocate array of 5 integers
scores[0] = 100;

delete[] scores;             // Free array - note the brackets!

أخطاء شائعة يجب تجنبها:

// Memory leak - forgot to delete
int* ptr = new int(10);
ptr = new int(20);    // Lost access to first allocation!

// Dangling pointer - using after delete
delete ptr;
*ptr = 5;             // Undefined behavior!

// Mismatched delete
int* arr = new int[10];
delete arr;           // Wrong! Should be delete[]

بعد الحذف، قم بتعيين المؤشرات إلى nullptr لتجنب إعادة الاستخدام عن طريق الخطأ.

جرّب بنفسك

#include <iostream>
#include <string>
#include "MessageBox.h"
using namespace std;

int main() {
    int capacity;
    int numMessages;
    
    // قراءة السعة وعدد الرسائل
    cin >> capacity;
    cin >> numMessages;
    cin.ignore(); // مسح السطر الجديد بعد الرقم
    
    // TODO: إنشاء MessageBox على الـ heap باستخدام new
    
    // TODO: قراءة وإضافة جميع الرسائل إلى MessageBox
    for (int i = 0; i < numMessages; i++) {
        string message;
        getline(cin, message);
        // إضافة الرسالة إلى MessageBox
    }
    
    // TODO: استدعاء printAll() لعرض جميع الرسائل
    
    // TODO: حذف MessageBox لتحرير الذاكرة
    // تذكر تعيين المؤشر إلى nullptr بعد الحذف
    
    return 0;
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming