दिलचस्प पोस्ट
क्या मैं एक HTML <canvas> तत्व पर एंटीअलियाज़िंग को बंद कर सकता / सकती हूं? नेस्टेड फॉर-लूप की समय की जटिलता रिवर्स इंजीनियरिंग से निष्पादन योग्य रक्षा? निष्पादन कार्य के लिए असफल: एप: एंड्रॉइड स्टूडियो में डिबग जावावाथजवाक को संकलित करें क्या पासवर्ड संग्रहण के लिए SHA-1 सुरक्षित है? अद्वितीय समाधान के साथ सुडोकू बोर्ड कैसे उत्पन्न करें जावा 7 कोड को जावा 7 जेवीएम पर चलाने के लिए संकलित किया जा सकता है? एंड्रॉइड: एक ListView से बच्चे के दृश्यों तक पहुंचें पहेली गेम में जेपीनेल अपडेट नहीं कर रहा है सी ++ कंपाइलर्स ऑपरेटर == और ऑपरेटर को परिभाषित क्यों नहीं करते! =? data.frame समूह द्वारा कॉलम एंड्रॉइड एसडीके स्थापना जेडीके नहीं मिलती अपेक्षित यदि कंडीशनल वैधीकरण विशेषता जावा Servlets का उपयोग करते हुए पोस्ट वैरिएबल एक्सेस करना कैसे एक जावास्क्रिप्ट में अपने मूल्यों के द्वारा एक साहचर्य सरणी सॉर्ट करने के लिए?

क्या वही सदिश से एक तत्व को पुश_बैक करना सुरक्षित है?

vector<int> v; v.push_back(1); v.push_back(v[0]); 

यदि दूसरा पुश_बैक एक रीअलोकेशन का कारण बनता है, तो सदिश में पहले पूर्णांक का संदर्भ अब मान्य नहीं होगा। तो यह सुरक्षित नहीं है?

 vector<int> v; v.push_back(1); v.reserve(v.size() + 1); v.push_back(v[0]); 

यह सुरक्षित करता है?

वेब के समाधान से एकत्रित समाधान "क्या वही सदिश से एक तत्व को पुश_बैक करना सुरक्षित है?"

ऐसा लगता है कि http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#526 इस समस्या को संबोधित किया (या कुछ इसी तरह से) मानक में एक संभावित दोष के रूप में:

1) कॉन्स्ट संदर्भ द्वारा ली गई पैरामीटर फ़ंक्शन के निष्पादन के दौरान बदला जा सकता है

उदाहरण:

दिए गए std :: vector v:

v.insert (v.begin (), वी [2]);

v [2] वेक्टर के तत्वों को हिलाने से बदला जा सकता है

प्रस्तावित प्रस्ताव यह था कि यह एक दोष नहीं था:

वेक्टर :: डाट (आईटर, वैल्यू) काम करने के लिए आवश्यक है क्योंकि मानक इसके लिए काम नहीं करने के लिए अनुमति नहीं देता है।

हां, यह सुरक्षित है, और मानक पुस्तकालय कार्यान्वयन हुप्स के माध्यम से कूदते हैं ताकि ऐसा किया जा सके।

मेरा मानना ​​है कि कार्यान्वयनकर्ता इस आवश्यकता को वापस 23.2 / 11 तक ट्रेस कर लेते हैं, लेकिन मैं यह नहीं समझ सकता कि कैसे और मुझे और अधिक ठोस नहीं मिल सकता है। सबसे अच्छा मुझे मिल सकता है यह आलेख है:

http://www.drdobbs.com/cpp/copying-container-elements-from-the-c-li/240155771

लिबसी ++ और लिबस्टडीसी ++ के कार्यान्वयन के निरीक्षण से पता चलता है कि वे भी सुरक्षित हैं।

मानक सुरक्षित होने के लिए आपका पहला उदाहरण भी गारंटी देता है सी ++ 11 उद्धरित

[Sequence.reqmts]

3 टेबल्स 100 और 101 में … X एक अनुक्रम कंटेनर वर्ग को दर्शाता है, a X मान को T प्रकार के तत्वों को दर्शाता है, … t एक लार्वेल या X::value_type एक const rvalue को X::value_type

16 टेबल 101 …

अभिव्यक्ति a.push_back(t) रिटर्न टाइप void a.push_back(t) सिमेंटिक्स t. की एक प्रति a.push_back(t) आवश्यक है: T CopyInsertable X में होगा कंटेनर deque , deque , list , vector

इसलिए भले ही यह बिल्कुल तुच्छ नहीं है, कार्यान्वयन की गारंटी होना चाहिए कि push_back करते समय यह संदर्भ को अमान्य नहीं करेगा।

यह स्पष्ट नहीं है कि पहला उदाहरण सुरक्षित है, क्योंकि push_back का सरलतम कार्यान्वयन पहले आवश्यक वेक्टर को पुनः आवंटित करना होगा, और फिर संदर्भ की प्रतिलिपि करें।

लेकिन कम से कम यह दृश्य स्टूडियो 2010 के साथ सुरक्षित है। push_back कार्यान्वयन के मामले को विशेष रूप से push_back है जब आप सदिश में एक तत्व वापस धक्का देते हैं। कोड निम्नानुसार संरचित है:

 void push_back(const _Ty& _Val) { // insert element at end if (_Inside(_STD addressof(_Val))) { // push back an element ... } else { // push back a non-element ... } } 

यह मानक से कोई गारंटी नहीं है, लेकिन एक अन्य डेटा बिंदु के रूप में, v.push_back(v[0]) LLVM के libc ++ के लिए सुरक्षित है

libc ++ का std::vector::push_back कॉल __push_back_slow_path जब उसे मेमोरी को पुनः __push_back_slow_path करने की आवश्यकता होती है:

 void __push_back_slow_path(_Up& __x) { allocator_type& __a = this->__alloc(); __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), size(), __a); // Note that we construct a copy of __x before deallocating // the existing storage or moving existing elements. __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__v.__end_), _VSTD::forward<_Up>(__x)); __v.__end_++; // Moving existing elements happens here: __swap_out_circular_buffer(__v); // When __v goes out of scope, __x will be invalid. } 

पहला संस्करण निश्चित रूप से सुरक्षित नहीं है:

मानक लाइब्रेरी कंटेनर या स्ट्रिंग सदस्य फ़ंक्शन को कॉल करके प्राप्त किए जाने वाले चालकों पर संचालन अंतर्निहित कंटेनर का उपयोग कर सकता है, लेकिन इसे संशोधित नहीं करेगा। [नोट: विशेष रूप से, कंटेनर के संचालन जो उस कंटेनर से जुड़ी थेरोटरों के संचालन के साथ आईटेरेटर्स का विरोध करते हैं। – अंत नोट]

खंड 17.6.5.9 से


ध्यान दें कि यह डेटा दौड़ का हिस्सा है, जो लोग सामान्य रूप से थ्रेडिंग के संयोजन के बारे में सोचते हैं … लेकिन वास्तविक परिभाषा में "संबंधों से पहले" होता है, और मुझे push_back के कई दुष्प्रभावों के बीच कोई क्रमबद्ध रिश्ते नहीं दिखाई देता यहां खेलने में, अर्थात् संदर्भ अमान्यता को नई पूंछ तत्व प्रतिलिपि बनाने के संबंध में आदेश के रूप में परिभाषित नहीं किया गया है।

यह पूरी तरह सुरक्षित है

आपके दूसरे उदाहरण में आपके पास है

 v.reserve(v.size() + 1); 

जो आवश्यक नहीं है क्योंकि अगर वेक्टर अपने आकार से बाहर निकल जाता है, तो यह reserve निरूपित करेगा

वेक्टर इस सामान के लिए जिम्मेदार है, न कि आप।

दोनों सुरक्षित हैं क्योंकि पुश_बैक मूल्य की प्रतिलिपि करेगा, न कि संदर्भ। यदि आप पॉन्टरों को संचय कर रहे हैं, तो वेक्टर के संबंध में अभी भी सुरक्षित है, लेकिन अभी पता है कि आपके पास वेक्टर के दो तत्व हैं जो उसी डेटा की ओर इशारा करते हैं।

धारा 23.2.1 सामान्य कंटेनर आवश्यकताएँ

16

  • a.push_back (टी) टी की एक प्रति संलग्न करता है आवश्यक है: टी CopyInsertable एक्स में होगा
  • एक पीयूश_बैक (आरवी) आरवी की एक प्रति संलग्न करता है। आवश्यक है: टी को स्थानांतरित किया जा सकेगा एक्स में।

Push_back के कार्यान्वयन को इसलिए सुनिश्चित करना चाहिए कि v[0] की एक प्रति डाली गई है। काउंटर उदाहरण से, एक कार्यान्वयन को मानते हुए कि प्रतिलिपि बनाने से पहले पुन: निर्दिष्ट करना होगा, यह निश्चित रूप से v[0] की एक प्रति संलग्न नहीं करेगा और जैसे कि चश्मा का उल्लंघन करना।

23.3.6.5/1 से: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid. पुनरोद्धार का Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid. बनता है Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid.

चूंकि हम अंत में डालने जा रहे हैं, यदि वेक्टर का आकार बदलना नहीं है तो कोई भी संदर्भ अमान्य नहीं होगा। इसलिए यदि वेक्टर की capacity() > size() तो यह काम की गारंटी है, अन्यथा यह अनिर्धारित व्यवहार होने की गारंटी है।