C++ / الأساسي / الدرس 5
السلاسل والمتجهات والوصول الصالح
استخدم الحاويات القياسية المالكة للنص والتسلسلات، وافهم الفهارس والتكرار وإبطال المراجع قبل الوصول إلى العناصر.
في هذه الصفحة
أهداف الدرس
- معالجة std::string وstd::vector عبر عملياتهما العامة.
- تمييز الحجم والسعة وفهارس العناصر الصالحة.
- تمييز عدّ بايتات UTF-8 وحالات إبطال المكررات.
السلسلة تملك تسلسل محارف
تدير std::string تخزين محارفها وتحرره تلقائيًا. ينسخ إنشاؤها من نص حرفي المحارف المطلوبة إلى كائن السلسلة. يجمع وصل السلاسل نصًا مفيدًا دون حساب مؤشرات مخازن يدويًا. تعيد size عدد عناصر char، وهي بايتات في أنظمة UTF-8 المعتادة، لا عدد الحروف المرئية. يستخدم المقرر ASCII في أمثلة الإخراج ليكون العد محمولًا فيها. يحتاج النص العربي إلى سياسة ترميز ومكتبة تدعم Unicode عندما تهم حدود الحروف المركبة أو التطبيع أو عرض النص.
تحويل سلسلة مملوكة بأمان
يبدأ المثال الأول بكلمة مملوكة ويضيف علامة ترقيم ويغيّر العنصر الأول بعد التحقق من أن السلسلة غير فارغة. لا يجري operator[] فحصًا عامًا للحدود، ولذلك تستند صلاحية الفهرس صفر إلى ذلك الشرط. توفر at وصولًا مفحوصًا وترمي std::out_of_range عند فهرس غير صالح. اختر الوصول المفحوص عند الحدود غير المؤكدة بدل توقع تشخيص الفهرس الخاطئ من كل تطبيق. قد تتضمن السلسلة محارف صفرية داخلية، لذا فإن حجمها هو المرجع لطول تسلسلها في C++.
#include <iostream>
#include <string>
int main() {
std::string word{"code"};
word += "!";
if (!word.empty()) { word[0] = 'C'; }
std::cout << word << " " << word.size() << "\n";
}
Code! 5
يضيف الإلحاق عنصرًا واحدًا. يبرّر الفحص الفهرس صفر، ويبقى في السلسلة خمسة محارف ASCII.
الحجم ينشئ عناصر والسعة تحجز تخزينًا
تملك std::vector<T> تسلسلًا متجاورًا من كائنات T. الحجم عدد العناصر الموجودة، والسعة مقدار التخزين المتاح قبل احتياج النمو إلى إعادة تخصيص. تغيّر reserve السعة دون إنشاء عناصر، بينما تغيّر resize عدد العناصر. لذلك لا يجعل حجز عشر خانات الفهرس تسعة صالحًا في متجه فارغ. تضيف push_back عنصرًا وتحدّث الحجم. فضّل vector على مصفوفة ديناميكية محجوزة يدويًا لأنها تدير الإنشاء والإتلاف والتخزين معًا. ولا تخلط عمر كائن المتجه بعمر مؤشر مستعار إلى عناصره.
التكرار دون فهرسة غير لازمة
تعبّر for المبنية على النطاق عن زيارة كل عنصر قائم. استخدم متغيّرًا بالقيمة لنسخة صغيرة للقراءة، وauto& لتعديل مقصود، وconst auto& لاستعارة كائنات أكبر للقراءة. يحجز المثال سعة ويضيف درجة رابعة ثم يجمع العناصر الفعلية. لا تفحص الحلقة السعة غير المستخدمة. في منطق الفهارس يبدأ المجال الصالح بصفر وينتهي قبل size، وتحتاج السلسلة الفارغة إلى عناية. تتفادى المقارنة index < size حساب size ناقص واحد الذي قد يلتف عندما يكون الحجم غير ذي إشارة وفارغًا.
#include <iostream>
#include <vector>
int main() {
std::vector<int> scores{2, 4, 6};
scores.reserve(8);
scores.push_back(8);
int total{};
for (int score : scores) { total += score; }
std::cout << scores.size() << " " << total << "\n";
}
4 20
هناك أربعة عناصر مجموعها عشرون. لا تُطبع السعة عمدًا لأن قيمتها الدقيقة ليست جزءًا من عقد المثال.
النمو قد يبطل المستعيرين
تبطل إعادة تخصيص المتجه كل المؤشرات والمراجع والمكررات إلى تخزينه القديم. وحتى دون إعادة تخصيص يبطل الإلحاق مكرر النهاية القديم، ويمحو الحذف صلاحية المكررات والمراجع عند الموضع المحذوف وما بعده. تجنب الإلحاق بالمتجه نفسه أثناء اجتيازه بحلقة نطاقية. اجمع التغييرات منفصلة أو صمّم خوارزمية فهارس بعناية. قد تقلل reserve إعادة التخصيص لكنها لا تثبت صلاحية العمر لكل العمليات المقبلة. أعد الحصول على الوصول بعد التعديل البنيوي ووثّق متى تبطل العروض المعادة.
الأخطاء الشائعة وإصلاحها
تعذر الوصول الآمن إلى عناصر متجه محجوز السعة.
- لماذا يحدث؟
- حجزت reserve تخزينًا دون زيادة الحجم.
- كيف تصلحه؟
- أضف عناصر أو استخدم resize قبل الوصول.
- كيف تتجنب تكراره؟
- افحص الحجم لا السعة عند التحقق من الفهرس.
مرجع عنصر يفشل بعد push_back.
- لماذا يحدث؟
- أعاد النمو تخصيص تخزين العناصر.
- كيف تصلحه؟
- أعد الحصول على المرجع بعد التعديل أو غيّر التصميم.
- كيف تتجنب تكراره؟
- تتبّع العمليات المبطلة لكل عنصر مستعار.
حجم سلسلة عربية يختلف عن عدد الحروف المرئية.
- لماذا يحدث؟
- يخزّن UTF-8 كثيرًا من المحارف في عدة بايتات.
- كيف تصلحه؟
- استخدم عدًّا يدعم Unicode ومناسبًا للمهمة.
- كيف تتجنب تكراره؟
- حدّد هل المطلوب بايتات أم نقاط ترميز أم وحدات مرئية.
اختبر فهمك
1. ابدأ بمتجه فارغ واحجز عشرين ثم أضف 3 و7. حدّد الفهارس الصالحة ومجموعه دون افتراض السعة الدقيقة.
اعرض الحل المشروح
بعد reserve يكون الحجم صفرًا ولا يوجد فهرس عنصر صالح. وبعد استدعاءي push_back يصبح الحجم اثنين، فيصلح الفهرسان صفر وواحد فقط. المجموع عشرة. السعة عشرون على الأقل بعد نجاح الحجز وقد يخصص التطبيق أكثر. يرمي الوصول إلى الفهرس اثنين عبر at استثناء بدل توفير عنصر ثالث.
2. يحفظ تطبيق مؤشرًا إلى أول عنصر في متجه ثم يلحق عناصر كثيرة. اقترح طريقة آمنة لتذكّر العنصر المنطقي المحدد.
اعرض الحل المشروح
احفظ فهرس العنصر إذا كان التطبيق يلحق فقط ولا يعيد الترتيب أو يحذف عناصر سابقة. بعد النمو افحص الفهرس مقابل الحجم الحالي واحصل على مرجع جديد. إذا أمكن ترتيب العناصر أو حذفها فاستخدم معرّفًا ثابتًا وابحث عنه. لا يصبح مؤشر إلى تخزين قديم آمنًا لمجرد بقاء القيمة المحددة في مكان آخر.
أهم ما تعلمته
- استخدم الحاويات المالكة وميّز الحجم من السعة.
- افحص الحدود وسجّل قواعد إبطال الصلاحية.
- عدد البايتات ليس طولًا عامًا للنص.