ذاكرة Stack مقابل Heap
جزء من قسم Object Oriented Programming في رحلة C++ على Coddy — الدرس 12 من 104.
تستخدم برامج C++ منطقتين رئيسيتين للذاكرة: الـ stack والـ heap. إن فهم مكان وجود الكائنات (objects) الخاصة بك أمر بالغ الأهمية لكتابة كود فعال وخالٍ من الأخطاء.
تُعد منطقة المكدس (stack) ذاكرة سريعة وتلقائية. المتغيرات التي يتم التصريح عنها داخل الدوال تعيش هنا ويتم تدميرها تلقائيًا عندما تخرج عن نطاق العمل (scope).
void example() {
int x = 10; // تخصيص في المكدس (Stack allocation)
Player player; // تخصيص في المكدس - يتم تدميره تلقائياً
} // يتم تدمير x و player هناتعد الـ heap ذاكرة أكبر ولكنها أبطأ تديرها يدوياً. تبقى الكائنات الموجودة في الـ heap حتى تقوم بحذفها بشكل صريح.
void example() {
Player* player = new Player(); // تخصيص في الذاكرة الحرة (Heap)
// الكائن player يظل موجوداً حتى يتم حذفه
delete player; // يتطلب تنظيفاً يدوياً
}الاختلافات الرئيسية:
| Stack (المكدس) | Heap (الكومة) |
|---|---|
| تخصيص سريع | تخصيص أبطأ |
| حجم محدود | سعة كبيرة |
| تنظيف تلقائي | يتطلب تنظيفاً يدوياً |
| كائنات ذات حجم ثابت | كائنات ذات حجم ديناميكي |
استخدم تخصيص المكدس (stack allocation) للكائنات الصغيرة وقصيرة العمر. استخدم تخصيص الكومة (heap allocation) عندما تحتاج الكائنات إلى البقاء لفترة أطول من نطاقها أو عندما يتم تحديد حجمها في وقت التشغيل.
نسيان حذف ذاكرة الكومة (heap memory) يسبب تسربات الذاكرة (memory leaks)، وهي مصدر شائع للأخطاء في برامج C++.
التحدي
سهلدعونا نستكشف الفرق بين ذاكرة المكدس (stack) وذاكرة الكومة (heap) من خلال بناء فئة Counter بسيطة تتبع كيفية إنشاء الكائنات وتدميرها.
ستقوم بإنشاء ملفين لتنظيم الكود الخاص بك:
Counter.h: قم بتعريف فئةCounterمع سمةnameخاصة (string). قم بتضمين منشئ (constructor) يأخذ اسماً ويطبع"Creating: <name>"، ومدمراً (destructor) يطبع"Destroying: <name>". أضف طريقةgetName()لإرجاع اسم العداد.main.cpp: قم بتوضيح تخصيص الذاكرة في كل من المكدس والكومة. اقرأ اسماً من المدخلات، ثم:- قم بإنشاء
Counterمخصص في المكدس (stack-allocated) باستخدام ذلك الاسم - قم بإنشاء
Counterمخصص في الكومة (heap-allocated) بالاسم"HeapCounter" - اطبع كلا اسمي العدادين بالتنسيق
"Stack: <name>"و"Heap: <name>" - احذف العداد المخصص في الكومة لمنع تسرب الذاكرة (memory leak)
- قم بإنشاء
راقب كيف تظهر رسائل المنشئ والمدمر بترتيبات مختلفة بناءً على وقت إنشاء وحذف كل كائن. سيتم تدمير كائن المكدس تلقائياً عند انتهاء main()، بينما يجب حذف كائن الكومة صراحةً.
قم بتضمين ملف الرأس الخاص بك في main.cpp باستخدام #include "Counter.h".
ورقة مرجعية
تستخدم برامج C++ منطقتين رئيسيتين للذاكرة: المكدس (stack) والكومة (heap).
المكدس (stack) هو ذاكرة تلقائية وسريعة. المتغيرات المعلن عنها داخل الدوال تعيش هنا ويتم تدميرها تلقائيًا عندما تخرج عن النطاق:
void example() {
int x = 10; // تخصيص في المكدس (Stack allocation)
Player player; // تخصيص في المكدس - يتم تدميره تلقائيًا
} // يتم تدمير x و player هناالكومة (heap) هي ذاكرة أكبر ولكنها أبطأ تديرها يدويًا. الكائنات الموجودة في الكومة تستمر حتى تقوم بحذفها صراحةً:
void example() {
Player* player = new Player(); // تخصيص في الكومة (Heap allocation)
// player يظل موجودًا حتى يتم حذفه
delete player; // يتطلب تنظيفًا يدويًا
}الاختلافات الرئيسية:
| المكدس (Stack) | الكومة (Heap) |
|---|---|
| تخصيص سريع | تخصيص أبطأ |
| حجم محدود | سعة كبيرة |
| تنظيف تلقائي | يتطلب تنظيفًا يدويًا |
| كائنات ثابتة الحجم | كائنات ديناميكية الحجم |
استخدم تخصيص المكدس للكائنات الصغيرة قصيرة العمر. استخدم تخصيص الكومة عندما تحتاج الكائنات إلى البقاء لفترة أطول من نطاقها أو عندما يتم تحديد حجمها في وقت التشغيل. نسيان حذف ذاكرة الكومة يؤدي إلى تسرب الذاكرة (memory leaks).
جرّب بنفسك
#include <iostream>
#include <string>
#include "Counter.h"
using namespace std;
int main() {
// قراءة الاسم من المدخلات
string inputName;
cin >> inputName;
// TODO: إنشاء Counter مخصص في الـ stack باستخدام inputName
// TODO: إنشاء Counter مخصص في الـ heap باسم "HeapCounter"
// TODO: طباعة اسم عداد الـ stack بتنسيق "Stack: <name>"
// TODO: طباعة اسم عداد الـ heap بتنسيق "Heap: <name>"
// TODO: حذف العداد المخصص في الـ heap لمنع تسرب الذاكرة (memory leak)
return 0;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات الـ OOP
الملفات الخارجيةبناء وتجميع (Compilation) لغة C++ملفات الـ Header وملفات الـ Sourceالـ Namespaces والـ Scopeمقدمة في الـ OOP في C++الـ Classes مقابل الـ Objectsالمؤشر 'this'الـ Methods (الدوال الأعضاء)الـ Attributes (بيانات الأعضاء)أساسيات الـ Ctors والـ Dtorsمراجعة - آلة حاسبة بسيطة4خصائص الـ Class
أعضاء الـ Instance مقابل الـ Staticدوال الـ Getters والـ Settersدوال الأعضاء الثابتة (Const)الكلمة المفتاحية Mutableالدوال والمتغيرات الساكنة (Static)الدوال والفئات الصديقة (Friend)مراجعة - مدير الحساب البنكي7الوراثة
الوراثة الأساسيةمستويات الوصول في الوراثةترتيب استدعاء الـ Ctor والـ Dtorإعادة تعريف الدوال (Method Overriding)الدوال الافتراضية والـ VTableالوراثة المتعددةالوراثة الافتراضيةمراجعة - هيكلية الموظفين10نظرة عامة على STL
نظرة عامة وفلسفة STLحاويات STLالـ Iteratorsخوارزميات STLالـ Functors وتعبيرات Lambdaمراجعة - تكرار الكلمات13أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factory و Abstract Factoryنمط Builderنمط Observerنمط Strategy2إدارة الذاكرة
ذاكرة Stack مقابل Heapالمؤشرات والمراجعالذاكرة الديناميكية (new/delete)المؤشرات الذكية في C++RAII في C++مراجعة - مدير المصفوفات الديناميكية5التغليف (Encapsulation)
محددات الوصول في C++محددات الوصول بشكل متعمقإخفاء المعلوماتStruct مقابل Classالأصناف المتداخلة والداخليةمراجعة - نظام سجلات الطلاب8تعدد الأشكال (Polymorphism)
تعدد الأشكال: وقت التجميع مقابل وقت التشغيلالتحميل الزائد للدوال (Function Overloading)مراجعة الدوال الافتراضية (Virtual Functions)الدوال الافتراضية البحتة (Pure Virtual Functions)الأصناف المجردة (Abstract Classes)تصميم الواجهات (Interface) في C++التحويل الديناميكي (Dynamic Casting) و RTTIملخص - حاسبة الأشكال11مفاهيم OOP المتقدمة
التركيب مقابل الوراثةالـ Mixins عبر CRTPنمط Pimplمحو النوع (Type Erasure)أصناف Enum والأنواع القويةمعالجة الاستثناءات في OOPتسلسلات الاستثناءات المخصصة14أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط قالب الطريقةنمط الحالةنمط التركيبRAII كنمط3المنشئات والموادم
المنشئ الافتراضيالمنشئ ذو المعاملاتمنشئ النسخمنشئ النقلقوائم تهيئة المنشئالمنشئات المفوضةتعمق في الموادمقاعدة الثلاثة / الخمسة / الصفرمراجعة - فئة String6تحميل العوامل (Operator Overloading)
مقدمة في تحميل العواملتحميل العوامل الحسابيةتحميل عوامل المقارنةعوامل Streamتحميل عامل التعيينتحميل العوامل [] و ()عوامل تحويل النوعمراجعة - Matrix Class9القوالب
قوالب الدوالقوالب الأصنافتخصيص القوالبالقوالب المتغيرةأساسيات SFINAE و Type Traitsمراجعة - الحاويات العامة