2013-07-26 8 views
6

मान लीजिए मैं एक वर्ग जो एक आंतरिक बफर करने के लिए एक सूचक का प्रबंधन करता है: एक प्रतिलिपि सहित अबएक आंतरिक बफर करने के लिए एक सूचक के साथ अर्थ विज्ञान ले जाएँ

class Foo 
{ 
    public: 

    Foo(); 

    ... 

    private: 

    std::vector<unsigned char> m_buffer; 
    unsigned char* m_pointer; 
}; 

Foo::Foo() 
{ 
    m_buffer.resize(100); 
    m_pointer = &m_buffer[0]; 
} 

, मान लीजिए मैं भी सही ढंग से लागू कर दिया है शासन-ऑफ-द 3 सामान निर्माता जो प्रतियां आंतरिक बफर, और फिर आंतरिक बफर के नई प्रतिलिपि करने के लिए सूचक reassigns:

Foo::Foo(const Foo& f) 
{ 
    m_buffer = f.m_buffer; 
    m_pointer = &m_buffer[0]; 
} 

मैं भी चाल अर्थ विज्ञान लागू करते हैं तो यह सिर्फ सूचक कॉपी और बफर स्थानांतरित करने के लिए सुरक्षित है?

Foo::Foo(Foo&& f) : m_buffer(std::move(f.m_buffer)), m_pointer(f.m_pointer) 
{ } 

व्यवहार में, मैं जानता हूँ कि यह काम करना चाहिए, क्योंकि std::vector चाल निर्माता सिर्फ आंतरिक सूचक बढ़ रहा है - यह वास्तव में कुछ भी नहीं कर रहा है पुनः दिए तो m_pointer अभी भी एक वैध पते के लिए अंक। हालांकि, मुझे यकीन नहीं है कि मानक इस व्यवहार की गारंटी देता है या नहीं। std::vector स्थानांतरित करें अर्थशास्त्र की गारंटी है कि कोई पुनर्वितरण नहीं होगा, और इस प्रकार वेक्टर के सभी पॉइंटर्स/इटरेटर वैध हैं?

+0

मुझे पता है कि 'स्वैप' गारंटी देता है कि पॉइंटर्स अभी भी मान्य होंगे, लेकिन मुझे चाल के बारे में निश्चित नहीं है। –

+1

[संबंधित प्रश्न] (http://stackoverflow.com/q/17730689/1782465) पर इन मुद्दों के बारे में बहुत लंबी चर्चा हुई थी। मेरा मानना ​​है कि निष्कर्ष यह है कि एक कदम सीटीओआर में, बफर को केवल स्थानांतरित करने की गारंटी है। एक चाल असाइनमेंट ओप में, यह हो सकता है (आवंटक गुणों के आधार पर) कि बफर की प्रतिलिपि बनाई जाएगी। – Angew

+3

क्या आप चालक के शरीर में 'f.m_pointer = nullptr;' नहीं कर रहे हैं? यह एक ऐसे पते पर क्यों इंगित करता है जो उसके भाई बहन नहीं है? यदि आपके पास दो चर के बीच युग्मन है जो काफी तंग है, तो मैं कहूंगा कि क्रॉस युग्मन करने के बजाय इसे इस तरह रखें। – legends2k

उत्तर

4

मैं &m_buffer[0] फिर से करूंगा, बस इतना है कि आपको इन प्रश्नों से पूछना नहीं है। यह स्पष्ट रूप से सहज नहीं है, इसलिए ऐसा मत करो। और, ऐसा करने में, आपके पास कुछ भी खोने के लिए कुछ भी नहीं है। फायदे का सौदा।

Foo::Foo(Foo&& f) 
    : m_buffer(std::move(f.m_buffer)) 
    , m_pointer(&m_buffer[0]) 
{} 

मैं यह ज्यादातर के साथ आराम कर रहा हूँ क्योंकि m_pointer एक सदस्य m_buffer में दृश्य है, बल्कि सख्ती से अपने आप में एक सदस्य की तुलना में।

कौन सा सवाल पूछता है ... यह क्यों है? क्या आप &m_buffer[0] देने के लिए सदस्य फ़ंक्शन का पर्दाफाश नहीं कर सकते?

+0

ठीक है, मुझे लगता है कि अन्य सदस्य फ़ंक्शन पॉइंटर या कुछ अग्रिम कर सकते हैं। –

+1

हाँ, मामला हो सकता है। यदि यह सत्य है, तो यह 'm_pointer' वास्तव में एक _cursor_ है जिसका राज्य बफर से स्वतंत्र रूप से बदलने की उम्मीद है, तो यह उत्तर गलत है। लेकिन फिर मैं एक सूचक के बजाय एक सूचकांक भंडारण का प्रस्ताव होगा। शायद। और आप कम से कम सिर्फ इंडेक्स की प्रतिलिपि बना सकते हैं। –

2

इस हो सकता है ऐसा करने के लिए एक बेहतर तरीका:

class Foo 
{ 

    std::vector<unsigned char> m_buffer; 
    size_t m_index; 

    unsigned char* get_pointer() { return &m_buffer[m_index]; 
}; 

यानी बजाय, एक वेक्टर तत्व के लिए सूचक की दुकान यह सूचकांक की दुकान। इस तरह यह वैक्टर बैकिंग स्टोर की प्रतिलिपि बनाने/आकार बदलने के प्रति प्रतिरक्षा होगी।

+0

यह एक अच्छा जवाब है, लेकिन यह वास्तव में जवाब नहीं देता है कि मैंने क्या पूछा। मुझे पता है कि इंडेक्स का उपयोग करना सुरक्षित है, लेकिन मैं जानना चाहता हूं कि 'std :: vector' के चाल semantics iterators/पॉइंटर्स को अमान्य कर दिया गया है या नहीं? – Channel72

5

मैं ओपी के कोड पर टिप्पणी नहीं करूंगा। सभी मैं कर रहा हूँ इस सवाल aswering है:

std :: वेक्टर चाल अर्थ विज्ञान की गारंटी है कि कोई पुनः आबंटन हो जाएगा, और इस प्रकार सभी संकेत/iterators वेक्टर के लिए मान्य हैं करता है?

हाँ चालक के लिए हाँ। इसमें निरंतर जटिलता है (जैसा कि 23.2.1/4, तालिका 96 और नोट बी द्वारा निर्दिष्ट किया गया है) और इसी कारण से कार्यान्वयन के पास मूल vector (इसलिए कोई स्मृति पुनर्वितरण नहीं होता है) से स्मृति चोरी करने के अलावा कोई विकल्प नहीं है और मूल vector खाली कर रहा है ।

चाल असाइनमेंट ऑपरेटर के लिए नहीं। मानक के लिए केवल रैखिक जटिलता की आवश्यकता होती है (जैसा ऊपर वर्णित उसी अनुच्छेद और तालिका में निर्दिष्ट है) क्योंकि कभी-कभी एक पुनर्वितरण की आवश्यकता होती है। हालांकि, कुछ परिसंचरणों में, इसमें निरंतर जटिलता हो सकती है (और कोई पुनर्वितरण नहीं किया जाता है) लेकिन यह आवंटक पर निर्भर करता है। इतना के नव निर्मित दृष्टि से, (आप Howard Hinnanthere द्वारा ले जाया गया vector रों पर उत्कृष्ट प्रदर्शनी पढ़ सकते हैं।)

1

चाल निर्माण के मामले कदम दूसरे से एक कंटेनर से बफर करने के लिए गारंटी है वस्तु, ऑपरेशन ठीक है।

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

सामान्य रूप से वहां से स्थानांतरित होने के बाद आपके ऑब्जेक्ट का कोई उपयोग नहीं होगा (अनुमान है कि एक रावल्यू-रेफरेंस द्वारा बाध्य होना चाहिए यह एक रावल्यू होना चाहिए), तथ्य यह है कि आप बाहर निकल सकते हैं कास्टिंग द्वारा या std::move (जो मूल रूप से एक कास्ट है) का उपयोग करके एक लाभा, जिसमें केस कोड वास्तव में आपके ऑब्जेक्ट का उपयोग करने का प्रयास कर सकता है।

+1

नाजुकता का समाधान रावल्यू स्रोत के 'm_pointer' को शून्य करना है, लेकिन मुझे ऐसा करने के लिए एक प्रकार का उपयोग करना पसंद है, उदा। ['tidy_ptr'] (https://gitorious.org/redistd/redistd/blobs/master/include/redi/tidy_ptr.h), जो तब 'Foo (Foo &&) = डिफ़ॉल्ट की अनुमति देता है; सही काम करने के लिए। –

+0

@ जोनाथन वाकई: मैं विवरण में खुदाई नहीं करना चाहता था, क्योंकि मुझे विशेष रूप से पता नहीं है कि घटक का उपयोग कैसे किया जाता है। महत्वपूर्ण बात यह है कि विनाशक एक खाली वेक्टर के मामले को संभालने में सक्षम होना चाहिए और या तो सूचक को अनदेखा कर सकता है या इसे 0 पर सेट कर सकता है और फिर इसे अनदेखा कर सकता है। –

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