संकलक को के कॉल पर vector
से प्रतिलिपि होने की आवश्यकता होती है।
संकलक साबित कर सकते हैं, तो देखते हैं कि कोई नमूदार साइड इफेक्ट के साथ एक मान्य सार मशीन व्यवहार है (सार मशीन व्यवहार के भीतर, एक वास्तविक कंप्यूटर में नहीं है!) कि Foo
में std::vector
चलती है, तो वहां ऐसा कर सकते हैं।
आपके उपरोक्त मामले में, यह (चलती कोई सार मशीन दिखाई देने वाली दुष्प्रभाव नहीं है) सत्य है; हालांकि, संकलक इसे साबित करने में सक्षम नहीं हो सकता है।
संभवतः नमूदार व्यवहार जब एक std::vector<T>
है को कॉपी:
- तत्वों पर प्रतिलिपि कंस्ट्रक्टर्स लागू।
int
के साथ ऐसा करने से
- अलग-अलग समय पर डिफ़ॉल्ट
std::allocator<>
को आमंत्रित नहीं किया जा सकता है। यह ::new
और ::delete
(शायद) किसी भी मामले में, ::new
और ::delete
को उपरोक्त प्रोग्राम में प्रतिस्थापित नहीं किया गया है, इसलिए आप इसे मानक के तहत नहीं देख सकते हैं।
T
के विनाशक को विभिन्न वस्तुओं पर अधिक बार कॉल करना। int
के साथ देखने योग्य नहीं है।
vector
Foo
पर कॉल के बाद खाली नहीं है। कोई भी इसकी जांच नहीं करता है, इसलिए यह खाली होना-जैसा कि यह नहीं था।
- बाहरी वेक्टर के तत्वों के संदर्भ या पॉइंटर्स या इटरेटर उन लोगों के मुकाबले अलग हैं।
Foo
के बाहर वेक्टर के तत्वों में कोई संदर्भ, वैक्टर या पॉइंटर्स नहीं लेते हैं।
तुम कहते हो सकता है "लेकिन क्या हुआ अगर सिस्टम स्मृति से बाहर है कि नमूदार नहीं है, और वेक्टर बड़ी है, है?":
सार मशीन एक नहीं है "स्मृति से बाहर "हालत, गैर-बाधित कारणों के लिए यह कभी-कभी विफल रहता है (std::bad_alloc
फेंकता है)। यह असफलता सार मशीन का वैध व्यवहार है, और वास्तविक (वास्तविक) स्मृति (वास्तविक कंप्यूटर पर) आवंटित नहीं होने में विफल नहीं है, तब तक जब स्मृति के अस्तित्व में कोई अवलोकन दुष्प्रभाव नहीं होता है।
एक से थोड़ा अधिक खिलौना मामला:
int main() {
int* x = new int[std::size_t(-1)];
delete[] x;
}
जबकि इस कार्यक्रम स्पष्ट रूप से जिस तरह से बहुत अधिक स्मृति आबंटित करता है, संकलक कुछ भी आवंटित नहीं करने के लिए स्वतंत्र है।
हम आगे जा सकते हैं। यहां तक कि:
int main() {
int* x = new int[std::size_t(-1)];
x[std::size_t(-2)] = 2;
std::cout << x[std::size_t(-2)] << '\n';
delete[] x;
}
std::cout << 2 << '\n';
में तब्दील किया जा सकता है। वह बड़ा बफर अमूर्त मौजूद होना चाहिए, लेकिन जब तक आपका "असली" प्रोग्राम व्यवहार करता है-सार सारणी मशीन के रूप में, इसे वास्तव में इसे आवंटित नहीं करना पड़ता है।
दुर्भाग्य से, किसी भी उचित पैमाने पर ऐसा करना मुश्किल है। सी ++ प्रोग्राम से बहुत सारे तरीके और जानकारी लीक हो सकती है। तो ऐसे अनुकूलन पर भरोसा करते हैं (भले ही वे होते हैं) अच्छी तरह खत्म नहीं होने जा रहे हैं।
कि इस मुद्दे को भ्रमित कर सकते हैं new
के लिए कॉल वालों के बारे में कुछ सामान था, मैं अनिश्चित हूँ अगर यह भले ही एक प्रतिस्थापित ::new
था कॉल को छोड़ कानूनी होगा।
एक महत्वपूर्ण तथ्य यह है कि स्थितियों कि संकलक नहीं व्यवहार करने के लिए के रूप में अगर वहाँ एक प्रति था, भले ही std::move
आमंत्रित नहीं किया गया आवश्यक है देखते हैं है।
जब आप return
एक स्थानीय चर एक पंक्ति है कि return X;
और X
तरह लग रहा है में एक समारोह से पहचानकर्ता है, और कहा कि स्थानीय चर (स्टैक पर) स्वत: भंडारण की अवधि का है, आपरेशन परोक्ष एक कदम है, और कंपाइलर (यदि यह कर सकता है) रिटर्न वैल्यू और स्थानीय चर के अस्तित्व को एक ऑब्जेक्ट में बढ़ा सकता है (और move
भी छोड़ सकता है)।
एक ही सच है जब आप एक अस्थायी से एक वस्तु का निर्माण है - आपरेशन परोक्ष एक चाल (के रूप में यह एक rvalue के लिए बाध्य किया जाता है) और यह पूरी तरह से कदम दूर छिपाना कर सकते हैं।
इन दोनों मामलों में, कंपाइलर को इसे एक कदम (प्रतिलिपि नहीं) के रूप में पेश करने की आवश्यकता है, और यह चाल को बढ़ा सकता है।
std::vector<int> foo() {
std::vector<int> x = {1,2,3,4};
return x;
}
कि x
कोई std::move
है, फिर भी यह वापसी मान में ले जाया जाता है, और उस आपरेशन elided जा सकता है (x
और वापसी मान एक वस्तु में तब्दील किया जा सकता है)।
यह:
std::vector<int> foo() {
std::vector<int> x = {1,2,3,4};
return std::move(x);
}
ब्लॉक इलिजन, करता है इस के रूप में:
std::vector<int> foo(std::vector<int> x) {
return x;
}
और हम भी इस कदम रोक सकते हैं:
std::vector<int> foo() {
std::vector<int> x = {1,2,3,4};
return (std::vector<int> const&)x;
}
या यहाँ तक कि:
std::vector<int> foo() {
std::vector<int> x = {1,2,3,4};
return 0,x;
}
निहित चाल के नियमों के रूप में जानबूझकर नाजुक हैं। (0,x
बहुत खराब ,
ऑपरेटर का उपयोग है)।
अब, निहित-चाल यह पिछले ,
आधारित एक तरह के मामलों में होने वाली नहीं पर निर्भर की सलाह नहीं दी जाती है: मानक समिति पहले से ही एक अंतर्निहित-स्थानांतरित करने के लिए एक अंतर्निहित कॉपी मामला बदल गया है के बाद से अंतर्निहित-चाल की भाषा में जोड़ा गया था क्योंकि उन्होंने इसे हानिरहित समझा (जहां समारोह को A(B&&)
सीटीआर के साथ एक प्रकार देता है, और वापसी विवरण return b;
है जहां b
B
प्रकार है; सी ++ 11 रिलीज पर एक प्रतिलिपि बनाई गई, अब यह एक चाल है।) आगे अंतर्निहित कदम के विस्तार से इनकार नहीं किया जा सकता है: const&
पर स्पष्ट रूप से कास्टिंग करना संभवतः भविष्य में इसे रोकने के लिए सबसे विश्वसनीय तरीका है।
क्या आपके पास कोई लिंक है जहां मैं इस बारे में और जान सकता हूं कि यह कैसे काम करता है या सार मशीन कैसे परिभाषित की जाती है? – vu1p3n0x
@ vu1p3n0x सी ++ मानक की एक प्रति पाएं? [यहां एक मसौदा है] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf)। [यहां एक और है] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3376.pdf)। एक सार मशीन के संदर्भ में मानक में सी ++ का व्यवहार मानक में निर्दिष्ट किया गया है। – Yakk
बिल्कुल सही जवाब। –