2012-06-18 19 views
10

मुझे पता है कि वेक्टर तत्व विनाश आदेश सी ++ मानक द्वारा परिभाषित नहीं किया गया है (Order of destruction of elements of an std::vector देखें) और मैंने देखा कि मैंने जो सभी कंपाइलर चेक किए हैं, वे इस विनाश को शुरू से अंत तक करते हैं - जो मुझे गतिशील और स्थैतिक सरणी के विपरीत में आश्चर्यजनक है क्योंकि यह विपरीत है ऑर्डर, और यह रिवर्स ऑर्डर अक्सर सी ++ दुनिया में होता है।क्या वेक्टर तत्वों के विनाश आदेश को परिभाषित करना उचित होगा?

सख्त होने के लिए: मुझे पता है कि "कंटेनर सदस्यों ... का निर्माण और नष्ट करने के लिए किसी भी क्रम में नष्ट किया जा सकता है उदाहरण के लिए सम्मिलित करें और सदस्य कार्यों को मिटाना" और मैं इनके लिए किसी प्रकार का लॉग रखने के लिए कंटेनरों को वोट नहीं देता परिवर्तन"। मैं आगे के विनाश से मौजूदा वेक्टर विनाशक कार्यान्वयन को तत्वों के पिछड़े विनाश के लिए बदलने के लिए वोट दूंगा - कुछ और नहीं। और शायद यह नियम सी ++ मानक में जोड़ें।

और कारण क्यों? सरणी से वेक्टर में बदलना इस तरह से सुरक्षित होगा।

असली दुनिया का उदाहरण: हम सभी जानते हैं कि म्यूटेक्स लॉकिंग और ऑर्डर अनलॉक करना बहुत महत्वपूर्ण है। और यह सुनिश्चित करने के लिए कि अनलॉकिंग होता है - स्कोपगार्ड पैटर्न का उपयोग किया जाता है। फिर विनाश आदेश महत्वपूर्ण है। इस उदाहरण पर विचार करें। वहाँ - वेक्टर कारणों गतिरोध को सरणियों से स्विच - सिर्फ इसलिए कि उनके विनाश क्रम भिन्न होता है:

class mutex { 
public: 
    void lock() { cout << (void*)this << "->lock()\n"; } 
    void unlock() { cout << (void*)this << "->unlock()\n"; } 
}; 

class lock { 
    lock(const mutex&); 
public: 
    lock(mutex& m) : m_(&m) { m_->lock(); } 
    lock(lock&& o) { m_ = o.m_; o.m_ = 0; } 
    lock& operator = (lock&& o) { 
     if (&o != this) { 
      m_ = o.m_; o.m_ = 0; 
     } 
     return *this; 
    } 
    ~lock() { if (m_) m_->unlock(); } 
private: 
    mutex* m_; 
}; 

mutex m1, m2, m3, m4, m5, m6; 

void f1() { 
    cout << "f1() begin!\n"; 
    lock ll[] = { m1, m2, m3, m4, m5 }; 
    cout <<; "f1() end!\n"; 
} 

void f2() { 
    cout << "f2() begin!\n"; 
    vector<lock> ll; 
    ll.reserve(6); // note memory is reserved - no re-assigned expected!! 
    ll.push_back(m1); 
    ll.push_back(m2); 
    ll.push_back(m3); 
    ll.push_back(m4); 
    ll.push_back(m5); 
    cout << "f2() end!\n"; 
} 

int main() { 
    f1(); 
    f2(); 
} 

आउटपुट - f1() के लिए f2()

f1() begin! 
0x804a854->lock() 
0x804a855->lock() 
0x804a856->lock() 
0x804a857->lock() 
0x804a858->lock() 
f1() end! 
0x804a858->unlock() 
0x804a857->unlock() 
0x804a856->unlock() 
0x804a855->unlock() 
0x804a854->unlock() 
f2() begin! 
0x804a854->lock() 
0x804a855->lock() 
0x804a856->lock() 
0x804a857->lock() 
0x804a858->lock() 
f2() end! 
0x804a854->unlock() 
0x804a855->unlock() 
0x804a856->unlock() 
0x804a857->unlock() 
0x804a858->unlock() 
+1

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

+0

हम सभी जानते हैं कि जब निष्पादन का आदेश महत्वपूर्ण है, तो उन्हें किसी भी कंटेनर में रखना और उत्पन्न कोड को नष्ट करना अच्छा नहीं है। // कारावास नोटिस: मैं "हम सभी जानते हैं" बयान – stefaanv

+0

के साथ थोड़ा संदिग्ध हूं शायद आपने पढ़ने के बिना उत्तर दिया। एन स्कोपगार्ड (http://stackoverflow.com/questions/48647/does-scopeguard-use-really-lead-to-better-code) मैंने यहां उपयोग किया, विनाश आदेश मायने रखता है। यही कारण है कि मैंने इस उदाहरण का इस्तेमाल किया। – PiotrNycz

उत्तर

4

मुझे लगता है यह है से विनाश क्रम परिवर्तन देखने सी ++ का एक और मामला संकलक लेखकों को उनके वास्तुकला के लिए सबसे अधिक प्रदर्शन करने वाले कंटेनरों को लिखने में लचीलापन देता है। किसी विशेष क्रम में विनाश की आवश्यकता 0.001% मामलों में किसी सुविधा के लिए प्रदर्शन को नुकसान पहुंचा सकती है (मैंने वास्तव में कभी दूसरा उदाहरण नहीं देखा है जहां डिफ़ॉल्ट आदेश उपयुक्त नहीं था)। इस मामले में vector संगत डेटा है, इसलिए मैं पिछली बार फिर से चलने की बजाय हार्डवेयर की क्षमता का उपयोग कर रहा हूं और शायद बार-बार कैश को याद कर रहा हूं।

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

+0

इस उत्तर के लिए धन्यवाद। मैंने वास्तव में सोचा कि आगे और पिछड़े विनाश के बीच कोई प्रदर्शन अंतर नहीं है। – PiotrNycz

+0

मार्क - तो आपके उत्तर के अनुसार - सी ++ नियम एरे और सदस्य चर में रिवर्स ऑर्डर में विनाशकों को कॉल करने के लिए नियम - कारण यह है कि यह विनाश आगे के क्रम में इस तरह के कुशल नहीं है? – PiotrNycz

+0

@ user1463922 संभवतः प्रदर्शन प्रभाव, सही हो सकता है। निश्चित रूप से सदस्य चर के लिए हालांकि यह निर्माण/विनाश के एक निश्चित आदेश के लिए वांछनीय है। कंटेनर के लिए यह एक अलग मामला और पसंद है। –

4

Fwiw, libc++ आउटपुट:

f1() begin! 
0x1063e1168->lock() 
0x1063e1169->lock() 
0x1063e116a->lock() 
0x1063e116b->lock() 
0x1063e116c->lock() 
f1() end! 
0x1063e116c->unlock() 
0x1063e116b->unlock() 
0x1063e116a->unlock() 
0x1063e1169->unlock() 
0x1063e1168->unlock() 
f2() begin! 
0x1063e1168->lock() 
0x1063e1169->lock() 
0x1063e116a->lock() 
0x1063e116b->lock() 
0x1063e116c->lock() 
f2() end! 
0x1063e116c->unlock() 
0x1063e116b->unlock() 
0x1063e116a->unlock() 
0x1063e1169->unlock() 
0x1063e1168->unlock() 

यह उद्देश्यपूर्ण इस तरह से लागू किया गया था। मुख्य कार्य परिभाषित here है:

template <class _Tp, class _Allocator> 
_LIBCPP_INLINE_VISIBILITY inline 
void 
__vector_base<_Tp, _Allocator>::__destruct_at_end(const_pointer __new_last, false_type) _NOEXCEPT 
{ 
    while (__new_last != __end_) 
     __alloc_traits::destroy(__alloc(), const_cast<pointer>(--__end_)); 
} 

यह निजी कार्यान्वयन-विवरण कहलाती है size() हटना करने की जरूरत है, जब भी।

मुझे अभी तक सकारात्मक या नकारात्मक, इस दृश्य कार्यान्वयन विवरण पर कोई प्रतिक्रिया नहीं मिली है।

+1

यह जानना अच्छा लगता है कि इस तरह के कार्यान्वयन मौजूद हैं। – PiotrNycz

+0

मार्क द्वारा आगे के विनाश के लिए दिए गए तर्क के बारे में आप क्या सोचते हैं: "पीछे की ओर फिर से चलने की बजाय हार्डवेयर की क्षमता को देखने के लिए बुद्धिमानी से उपयोग करने की क्षमता और शायद बार-बार कैश गायब होने की क्षमता।" libC++ प्रदर्शन में अच्छा होने का दावा करता है ... – PiotrNycz

+0

यह एक संभावना है। लेकिन मैंने इस तरह का अंतर नहीं देखा है। न ही मैंने इसे देखा है। न ही मेरे किसी भी ग्राहक ने इस क्षेत्र में प्रदर्शन की समस्या की शिकायत की है (मुझे अन्य क्षेत्रों में प्रदर्शन शिकायतें मिली हैं - कुछ पहले ही संबोधित हैं, कुछ अभी भी मेरी टू-डू सूची पर हैं)। –

संबंधित मुद्दे