c++ - شركة - مضاعف القيمة الدفترية



هل يؤدي تغيير حجم المتجه إلى إبطال مكررات؟ (4)

قواعد إبطال مكررة هي محددة إلى حاوية.

الآن قد يكون إبطال المعاني 2 مع متجه:

  1. إنفاليداتيون = نقطة خارج النطاق المحدد بواسطة [بيجين، إند]
  2. إنفاليداتيون = تشير إلى كائن مختلف عن العنصر الأصلي

كما ترون، والثاني هو أكثر صرامة بكثير:

std::vector<int> myVector;
myVector.push_back(0);
myVector.push_back(1);

std::vector<int>::iterator it = myVector.begin(); // it points to 0
myVector.erase(it); // it points to 1
myVector.erase(it); // it == myVector.end()

في هذه الحالة، هو "صالح" في أنه هو دائما في نطاق شامل [تبدأ، نهاية] وهكذا يمكن استخدامها بأمان لأي عملية على ميفيكتور. من ناحية أخرى يبقى التعبير (* إيت) متغير: أولا يعود 0، ثم 1، ثم لديه سلوك غير معروف ...

وبصفة عامة، فإن الناس بدلا من التحدث عن الشرط الثاني، وإبطال مكررة يعني ببساطة أن (* أنها) قد لا تنتج نفس النتيجة كما كان من قبل.

الآن بعد أن قيل هذا، هناك عدة طرق لإبطال مكررة على ناقل (في الواقع، انها بنية أقل استقرارا من المحكمة الخاصة بلبنان).

خلال الإضافات من العناصر:

  • وهذا قد يؤدي إلى إعادة تخصيص (1) إذا myVector.size () == myVector.capacity ()، لأن التحقق من هذا هو عرضة للخطأ، ونحن عادة ما تعتبر أن أي إضافة سوف يبطل التكرار
  • إذا كنت تريد أن تكون "من الصعب إرضاءه" ويعرف أن إعادة تخصيص لا يتم تشغيل، ثم لا يزال لديك ما يدعو للقلق حول insert . يؤدي إدخال عنصر إلى إبطال المتغيرات التي تشير إلى هذا الموضع الحالي وجميع العناصر اللاحقة حيث يتم تحويل العناصر خطوة واحدة نحو نهاية المتجه.

أثناء إزالة العناصر:

  • لا يوجد إعادة تخصيص، حتى لو كانت المخزن المؤقت الآن أكبر بكثير من الحاجة. ومن الممكن فرض هذا على الرغم من، وذلك باستخدام يتقلص لتناسب لغة (2).
  • يتم إبطال جميع التكرارات التي تشير إلى العنصر الذي تمت إزالته. على وجه الخصوص، فإن "نهاية" السابق التكرار هو الآن خارج نطاق [بداية، نهاية] ولا يمكن استخدامها بأمان ضمن خوارزميات ستل على سبيل المثال.

(1) الهيكل الداخلي ل ستد :: ناقلات هو صفيف من T، وهذا يرجع إلى التوافق مع C- البرامج (باستخدام و MyVector.front () كعنوان المصفوفة) ولأنه يضمن التواصل والحد الأدنى (أي مقدار المساحة التي تأخذها بيانات المتجه الخاصة مقابل مقدار المساحة التي يشغلها جسم ما)

في أي لحظة، يمكنك معرفة عدد الكائنات التي يمكن أن يتحملها ناقلات باستخدام .capacity () الأسلوب.

عندما تريد إدراج كائن وليس المتجه القدرة اللازمة، يتم تشغيل استدعاء إلى .reserve (size_t) الأسلوب. هذه الطريقة، إذا كان عدد العناصر المطلوبة متفوقة على القدرة الحالية، يؤدي إلى إعادة تخصيص .

ثم يقوم المتجه بتخصيص صفيف جديد من العناصر (حجمه عموما 2 * n + 1 حيث n هو السعة الحالية)، ونسخ عناصر الصفيف الحالي إلى الصفيف الجديد، ويتجاهل الصفيف الحالي.

لأنه يتجاهل المصفوفة الحالية، يتم إبطال التكرارات الخاصة بك كما متجهات ناقلات هي مؤشرات بسيطة عموما (للكفاءة).

لاحظ أنه إذا تم تنفيذ التكرارات على النحو التالي: إشارة إلى المتجه + عدد، و ديرفيرنسينغ في الواقع * (& m_vector.front () + n) إعادة تخصيص لن يبطل لهم ... لكنها ستكون أقل كفاءة.

(2) يتقلص لتناسب: تحذير، وهذا يؤدي إلى نسخة من العناصر ويبطئ مكررة.

// myVector has 10 elements, but myVector.capacity() == 1000
myVector.swap(std::vector<int>(myVector));

فإنه أولا يخلق ناقلات مؤقتة، والتي سوف تخصص فقط الذاكرة بقدر ما هو مطلوب (مع الحد الأدنى اعتمادا على المكتبة)، ونسخ عناصر ميفكتور. ثم تبادل عملية تبادل المخازن المؤقتة من ميفكتور وهذه النسخة، وبالتالي ميفيكتور الآن حفرة المخزن المؤقت مع الحد الأدنى من الذاكرة اللازمة. في نهاية العملية يتم تدمير المؤقت والذاكرة التي يحملها صدر.

https://ffff65535.com

لقد وجدت أن هذا الرمز C ++:

vector<int> a;
a.push_back(1);
a.push_back(2);
vector<int>::iterator it = a.begin();
a.push_back(4);
cout << *it;

طباعة بعض عدد عشوائي كبير. ولكن إذا قمت بإضافة a.push_back(3) بين 3 و 4 خطوط، فإنه سيتم طباعة 1. يمكنك شرح لي؟


للرجوع إليها في المستقبل، وجميع أنواع المحكمة الخاصة بلبنان من الحكايات مثل هذا على موقع سغي على الانترنت: http://www.sgi.com/tech/stl/Vector.html

إذا كنت بحاجة إلى مكررات للبقاء صالحة بعد إضافة أو حذف لمجموعة، نلقي نظرة على نوع آخر من جمع، مثل قائمة.

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

راجع مقالة ويكيبيديا على Standard_Template_Library حاويات نقطة البداية. إذا كان لديك النقدية، وأنا أوصي "سكول ماير" فعالة ستل: 50 طرق محددة لتحسين استخدامك من مكتبة قالب قياسي ".

اعتذارات لعدم وجود روابط داعمة، أنا مبتدئ هنا وعدم وجود سمعة لنشر هذا مع أكثر من واحد.


يتم إبطال متجهات ناقلات فقط عندما يقوم ناقلات إعادة تخصيص.

الدعوة إلى push_back(4) تتسبب في ناقلات لتخصيص كتلة جديدة من الذاكرة - وهذا هو ما يجعل الخاص بك إينتيراتور لتصبح غير صالحة. عندما تستخدم أيضا push_back(3) ، يتم إجراء إعادة التخصيص ل push_back(4) بحيث يظل التكرار صالحا.


تحرير مع صياغة أكثر حذرا

نعم، تغيير حجم ناقلات قد يبطل كل تكرارات مشيرا إلى ناقلات.

يتم تنفيذ المتجه من خلال تخصيص مصفوفة داخليا حيث يتم تخزين البيانات. عندما ينمو المتجه، قد نفدت هذه المصفوفة من الفضاء، وعندما يفعل ذلك، يقوم المتجه بتخصيص جديد، أكبر، صفيف نسخ البيانات إلى ذلك ثم حذف مصفوفة القديمة.

لذا لم تعد المفكرات القديمة، التي تشير إلى الذاكرة القديمة، صالحة. إذا تم تغيير حجم المتجه لأسفل (على سبيل المثال بواسطة pop_back() )، ومع ذلك، يتم استخدام نفس المصفوفة. لم يتم تصغير حجم المصفوفة تلقائيا.

طريقة واحدة لتجنب هذا إعادة تخصيص (وإبطال المؤشر) هو استدعاء vector::reserve() أولا، لتخصيص مساحة كافية أن هذا النسخ ليست ضرورية. في حالتك، إذا اتصلت ب a.reserve(3) قبل عملية a.reserve(3) push_back() ، فإن المصفوفة الداخلية ستكون كبيرة بما فيه الكفاية بحيث يمكن تنفيذ عملية push_back من دون الحاجة إلى إعادة تخصيص المصفوفة، صالح.





iterator