مقدمة
اليوم ، نظرًا للتحسن والتكاليف المنخفضة للتكنولوجيا ، فإن حجم الذاكرة وقوة المعالجة ينمو بشكل مطرد.
وفقًا لقانون مور:
يتضاعف عدد الترانزستورات الموضوعة على شريحة دوائر متكاملة كل 24 شهرًا.
تجدر الإشارة إلى تغيير معلمتين:
- عدد الترانزستورات
- أبعاد الوحدة
يتم إسقاط نفس المبادئ على مقدار ذاكرة الوصول العشوائي (DRAM).
الآن مسألة الذاكرة ليست حادة ، حيث زاد حجم الذاكرة على مدى السنوات العشر الماضية 16 مرة لكل يموت.
معظم لغات البرمجة عالية المستوى (PL) هي بالفعل "خارج الصندوق" تختبئ عن العمل مع الذاكرة من المبرمج. وحيث أن هذا السؤال كان نائماً ، تظهر مجموعة جديدة من المبرمجين الذين لا يفهمون
أو لا يرغبون في فهم كيفية عمل العمل مع الذاكرة.
في هذا الموضوع ، سننظر في النقاط الرئيسية للعمل مع الذاكرة باستخدام مثال لغة C ++ ، لأنها واحدة من اللغات الأساسية القليلة التي تدعم العمل المباشر مع الذاكرة وتدعم OOP.
ما هو عليه؟
تجدر الإشارة هنا ، تم تصميم هذه المقالة للأشخاص الذين بدأوا للتو في C ++ أو يريدون فقط أن يكون لديهم فكرة عن الذاكرة الديناميكية.
في وقت التشغيل ، يحتفظ أي برنامج قطعة من الذاكرة لنفسه في DRAM. وتسمى جميع المساحة الحرة DRAM
"الكومة" (الإنجليزية "كومة"). يحدث تخصيص الذاكرة أثناء التنفيذ لاحتياجات البرنامج على وجه التحديد من الكومة ويسمى تخصيص الذاكرة الديناميكية.
المشكلة كلها هي أنه إذا لم تهتم بتنظيف الذاكرة المخصصة عندما لم تعد هناك حاجة إليها ، فقد يحدث ما يسمى تسرب للذاكرة ، حيث يتعطل نظامك
(البرنامج) ببساطة. اقترب من السيارة التي توقفت في منتصف الطريق لأن شخصًا ما نسي التزود بالوقود في الوقت المحدد.
ما يجب أن تعرفه بالفعلتم تجهيز معظم PLs الحديثة مع جامعي القمامة ومسح ذاكرتهم من تلقاء نفسها.
ومع ذلك ، قامت C ++ بتأسيس نفسها كواحدة من واجهات برمجة التطبيقات الأسرع أداءً ، جزئيًا لأن كل العمل مع الذاكرة فيه يتم يدويًا.
جديد وحذف
يمكن أن يكون تخصيص الذاكرة ثابتًا وديناميكيًا. يُطلق على التخصيص الثابت للذاكرة تخصيص لمرة واحدة للذاكرة أثناء التحويل البرمجي للبرنامج ، ولا يتغير مقدار الذاكرة الثابتة في وقت التشغيل. مثال كلاسيكي هو إعلان متغير عدد صحيح أو صفيف. ولكن ماذا لو كان المبرمج لا يعرف مقدمًا عدد العناصر المطلوبة في الحاوية؟
يُنصح باستخدام الذاكرة الديناميكية عند الضرورة لتنظيم تخصيص الذاكرة لاحتياجات البرنامج حسب الضرورة.
المشغل
الجديد مسؤول عن تخصيص الذاكرة الديناميكية في C ++ ،
والحذف مسؤول عن محوها.
إرجاع عامل التشغيل
الجديد نتيجة العملية مؤشر إلى مثيل جديد للفئة.
بناء الجملة هو هذا:
|
مؤشر نوع البيانات (T1) | * |
اسم المؤشر | =
جديد |
اكتب T1 |
بعد المشغل
الجديد ، يمكنك استخدام المُنشئ ، على سبيل المثال ، لتهيئة حقول الفصل.
تجدر الإشارة إلى أن نفس تسرب الذاكرة يحدث بالضبط عندما يفقد مبرمج السيطرة على تخصيصه.
من المهم أن تتذكر:
إذا كنت قد نسيت عن محو الذاكرة الديناميكية للعناصر غير الضرورية "المستهلكة" ، فستتأتى عاجلاً أو آجلاً لحظة حرجة عندما لا تكون في أي مكان ستأخذ منه الذاكرة.
مثال على تخصيص الذاكرة وتنظيفها:
int main{
لن يناقش هذا المقال ما يسمى بالمؤشرات "الذكية" ، لأن الموضوع واسع للغاية ، ولكن باختصار: "المؤشرات الذكية تعمل تلقائيًا جزئيًا على عملية مسح الذاكرة للمبرمج".
مؤشرات
المؤشرات هي المسؤولة عن العمل مع الذاكرة الديناميكية في C ++. هذا هو الموضوع الذي غنائم الشهية مبتدئين.
يمكنك إعلان مؤشر باستخدام العامل
* . بشكل افتراضي ، سوف يشير إلى منطقة عشوائية من الذاكرة. حتى نتمكن من الوصول إلى منطقة الذاكرة التي نحتاجها ، نحتاج إلى تمرير رابط (عامل التشغيل) إلى المتغير المطلوب.
المؤشر نفسه هو ببساطة عنوان خلية الذاكرة ، وللوصول إلى البيانات المخزنة في هذه الخلية ، يجب أن تكون مؤجلة.
تراجع مهم
إذا حاولت عرض المؤشر دون إلغاء التسجيل ، فبدلاً من القيمة من منطقة الذاكرة التي يشير إليها ، يتم عرض عنوان منطقة الذاكرة هذه.
لإلغاء تحديد مؤشر ، ما عليك سوى وضع عامل التشغيل * أمام اسمه.
int main() {

بالنظر إلى هذه الأمثلة ، أود أن أسأل: "لماذا يعد هذا ضروريًا إذا كان بإمكانك اشتقاق متغير على الفور؟"
مثال آخر:
لدينا فئة المبرمجين التي تصف أعضاء فريق من المبرمجين الذين
لا يعرفون المؤشرات. class Programmers{ public: Programmers(){} Programmers(int iWeight, int iAge){ this->weight = iWeight; this->age = iAge; } int weight; int age; }; int main() {
بهذه الطريقة ، يمكن التلاعب بالذاكرة كما يحلو لنا. وهذا هو السبب ، عند العمل مع الذاكرة ، يمكنك "إطلاق النار على نفسك". تجدر الإشارة إلى أن العمل مع المؤشر أسرع بكثير ، حيث لا يتم نسخ القيمة نفسها ، ولكن يتم تعيين رابط إلى عنوان معين فقط.
بالمناسبة ، توفر
هذه الكلمة الأساسية الشائعة مؤشرًا لكائن الفئة الحالي.
هذه المؤشرات في كل مكان.مثال على مؤشر في الحياة اليومية:تخيل موقفًا عندما تطلب طبقًا في مطعم. لتقديم طلب ، تحتاج فقط إلى الإشارة إلى الطبق في القائمة وستكون مستعدًا. بالطريقة نفسها ، يشير زائرو المطعم الآخرون إلى العنصر المطلوب في القائمة. وبالتالي ، فإن كل سطر في القائمة هو مؤشر إلى وظيفة الطهي في الطبق ، وقد تم إنشاء هذا المؤشر في مرحلة تصميم هذه القائمة نفسها.
العودة إلى المبرمجين لدينا. لنفترض الآن أننا نحتاج إلى نقل حقول الفصل إلى القسم
الخاص ، بما يتناسب مع مبدأ التغليف من OOP ، ثم نحتاج إلى الحصول على إمكانية الوصول للقراءة إلى هذه الحقول. لكن تخيل أنه ليس لدينا حقلان ، ولكن 100 ، ولهذا نحتاج إلى كتابة ملحقنا الخاص بكل منهما؟
المفسدحسنًا ، بالطبع لا ، أنا لا أفهم لماذا فتحت هذا المفسد.
للقيام بذلك ، سنجعل "أداة وصول" للنوع لاغية وننقل إليها بالرجوع إليها. معنى تمرير وسيطة حسب المرجع هو أن قيمة الوسيطة لا يتم نسخها ، ولكن يتم نقل عنوان الوسيطة الحقيقية فقط. وبالتالي ، عند تغيير قيمة هذه الوسيطة ، ستتغير أيضًا البيانات الموجودة في خلية الذاكرة الخاصة بالوسيطة الحالية.
يؤثر هذا أيضًا على الأداء الكلي ، نظرًا لأن تمرير وسيطة حسب المرجع أسرع من تمرير القيمة. وهذا ناهيك عن مجموعات كبيرة من العناصر.
على سبيل المثال ، ستعمل طريقة
getParams بداخلها على تغيير الوسائط الواردة وستقوم بتغيير قيمها ، بما في ذلك في النطاق ، من حيث تم استدعائها.
سوف يساعدنا المؤشر في تصفح الصفيف. من نظرية هياكل البيانات ، نعلم أن المصفوفة هي منطقة مستمرة من الذاكرة يتم ترتيب عناصرها واحدة تلو الأخرى.
هذا يعني أنه إذا قمت بتغيير قيمة المؤشر إلى عدد البايتات التي يشغلها العنصر في الصفيف ، فيمكنك الوصول إلى كل عنصر حتى يتجاوز المؤشر حدود المصفوفة.
قم بإنشاء مؤشر آخر يشير إلى العنصر الأول من مجموعة
المبرمجين .
class Programmers{ public: Programmers(){} Programmers(int iWeight, int iAge){ this->weight = iWeight; this->age = iAge; }

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