2017-03-14 23 views
11

किसी ऑब्जेक्ट पर std::move को कॉल करने के बाद, ऑब्जेक्ट का उपयोग करने के बाद भाषा संकलन त्रुटि क्यों नहीं करती है?std :: move के बाद किसी ऑब्जेक्ट का उपयोग करने के परिणामस्वरूप संकलन त्रुटि

क्या ऐसा इसलिए है क्योंकि संकलक के लिए इस स्थिति का पता लगाना संभव नहीं है?

+3

क्योंकि आप इसके साथ चीजें कर सकते हैं और आप इसका पुन: उपयोग कर सकते हैं। चलती वस्तु को एक वैध स्थिति में छोड़ देता है। – NathanOliver

+3

स्थानांतरित वस्तु की स्थिति को चालक द्वारा परिभाषित किया गया है। इसलिए जब तक चालक इसे अनुमति देता है तब तक इसका उपयोग करना ठीक है। – Dani

+2

'std :: move' ऑब्जेक्ट को 'T &&' पर रखता है, यह वास्तव में ऑब्जेक्ट में कुछ भी नहीं करता है। – lcs

उत्तर

0

प्रकृति वस्तु के बाद-स्थान राज्य को कार्यान्वयनकर्ता द्वारा परिभाषित किया गया है; कुछ मामलों में, किसी ऑब्जेक्ट को स्थानांतरित करना इसे पूरी तरह उपयोग करने योग्य स्थिति में छोड़ सकता है, जबकि अन्य में ऑब्जेक्ट को बेकार (या बदतर, किसी भी तरह उपयोग करने में खतरनाक) प्रदान किया जा सकता है।

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

(वास्तव में, निडर, यह एक अच्छा आधार उदा a Clang plugin के लिए वास्तव में कर सकता है,!)

+0

ऑब्जेक्ट पोस्ट की स्थिति 'std :: move' नहीं बदला था। यह सिर्फ एक फैंसी कास्ट है। यह वह फ़ंक्शन है जिसे (कन्स्ट्रक्टर मूव असाइनमेंट ऑपरेटर इत्यादि ले जाएं), जब आपने मूल ऑब्जेक्ट डाला है जो इसके राज्य को बदलता है। –

+0

@ रिचर्ड क्रिटन जो सच है w/r/t क्या है 'std :: move (...) 'तकनीकी अर्थ में, लेकिन यह एक कार्यान्वयनकर्ता को एक चालक कन्स्ट्रक्टर (और/या एक चाल असाइनमेंट ऑपरेटर) लिखने की अनुमति देता है जो करता है तथ्य एक वस्तु 'राज्य में हेरफेर। – fish2000

+0

@ फ्रैंकोइस एंड्रीक्स ओह वाह जो एक सूक्ष्म लेकिन महत्वपूर्ण बिंदु है, धन्यवाद! – fish2000

4

याद रखें, std::move एक rvalue संदर्भ के लिए एक डाली से ज्यादा कुछ नहीं है। अपने आप में वास्तव में कुछ भी नहीं ले जाता है। इसके अतिरिक्त, भाषा केवल यह बताती है कि ऑब्जेक्ट से स्थानांतरित एक वैध/विनाशकारी स्थिति में है, लेकिन इसके अलावा इसकी सामग्री के बारे में कुछ भी नहीं कहा जाता है - यह अभी भी बरकरार हो सकता है, ऐसा नहीं हो सकता है या (जैसे std::unique_ptr हो सकता है विशिष्ट सामग्री (nullptr) के लिए परिभाषित किया गया है) - यह सब इस बात पर निर्भर करता है कि चालक कन्स्ट्रक्टर/चाल-असाइनमेंट-ऑपरेटर लागू करता है।

तो, वस्तु से स्थानांतरित करने के लिए यह सुरक्षित/मान्य है या नहीं, पूरी तरह से विशिष्ट वस्तु पर निर्भर करता है। एक कदम के बाद std::unique_ptr पढ़ना, यह देखने के लिए कि यह nullptr उदाहरण के लिए बिल्कुल ठीक है - अन्य प्रकार के लिए; इतना नहीं।

3

इसे "कार्यान्वयन की गुणवत्ता" मुद्दा कहा जाता है: यह एक अच्छा संकलक या टूलचैन के लिए संभावित रूप से खतरनाक उपयोग के बाद चेतावनी जारी करने के लिए अधिक समझ में आता है, इसके बाद भाषा मानक औपचारिक रूप से इसे प्रतिबंधित करता है स्थितियों के एक निश्चित परिभाषित सेट में। आखिरकार, चाल के बाद कुछ उपयोग वैध होते हैं (जैसे कि std::unique_ptr का मामला, जो स्थानांतरित होने के बाद खाली होने की गारंटी है) जबकि अन्य मामलों को अपरिभाषित किया जा सकता है, आसानी से पता नहीं लगाया जा सकता है - सामान्य रूप से पता लगाना कि क्या कोई वस्तु है इसे स्थानांतरित करने के बाद उपयोग की जाने वाली समस्या के बराबर है।

आप चाल के बाद उपयोग पता लगाने के लिए बजना-सुथरा उपयोग कर सकते हैं: https://clang.llvm.org/extra/clang-tidy/checks/misc-use-after-move.html

8

सी में सामान्य सिद्धांत ++ भाषा डिजाइन है "प्रोग्रामर पर भरोसा"। std::move पर तर्क के बाद ऑब्जेक्ट के किसी भी उपयोग को अस्वीकार करने के साथ मैं कुछ मुद्दों पर विचार कर सकता हूं।

  • यह निर्धारित करने के लिए कि सामान्य मामले में std::move पर कॉल के बाद दिया गया उपयोग रोकथाम समस्या को हल करने के बराबर होगा। (दूसरे शब्दों में, यह नहीं किया जा सकता है।) आपको कुछ नियमों के साथ आना होगा जो वर्णन करते हैं कि "बाद" द्वारा आपके द्वारा क्या मतलब है, जिसे सांख्यिकीय रूप से निर्धारित किया जा सकता है।
  • सामान्य रूप से, यह किसी ऑब्जेक्ट को असाइन करने के लिए पूरी तरह से सुरक्षित है जो std::move पर तर्क है। (एक विशेष वर्ग एक दावा कर सकता है, लेकिन यह एक बहुत ही अजीब डिजाइन होगा।)
  • एक कंपाइलर के लिए यह कहना मुश्किल है कि कोई दिया गया कार्य कक्षा के नए मानों के तत्वों को असाइन करने जा रहा है या नहीं।
+0

आह, जानना अच्छा है [जंग ने हलिंग समस्या हल कर दी है] (http://typeinference.com/rust/2015/07/31/rust-ownership-part-i.html) –

+0

मुझे आश्चर्य है कि जब चलती है तो जंग क्या करता है एक सशर्त शाखा में होता है। यह शायद सुरक्षित खेलता है: यदि कोई शाखा होती है जहां एक कदम होता है, तो यह माना जाता है कि यह वास्तव में होता है। लेकिन यह कुछ प्रोग्रामों को अस्वीकार कर सकता है जो वैध हैं। – CygnusX1

+0

हां, जंग इसे सुरक्षित रखती है, यहां तक ​​कि ऐसे मामलों में जहां संकलक जानता है कि एक शाखा कभी निष्पादित नहीं कर सकती है। निम्नलिखित fn मुख्य() { println! ("हैलो वर्ल्ड") संकलित नहीं करता है; v1 = vec दें! [1, 2, 3]; v2 = v1 दें; यदि 0 == 1 { v2 = v1; } println! ("V1 [0] = {}", v1 [0]); } – KristianR

3

ऐसा इसलिए है क्योंकि हम अक्सर स्थानांतरित वस्तु से उपयोग करना चाहते हैं। std::swap के डिफ़ॉल्ट कार्यान्वयन पर विचार करें:

template<typename T> 
void swap(T& t1, T& t2) 
{ 
    T temp = std::move(t1); 
    t1 = std::move(t2); // using moved-from t1 
    t2 = std::move(temp); // using moved-from t2 
} 

आप संकलक आप हर बार जब आप std::swap का उपयोग चेतावनी देने के लिए नहीं करना चाहती।

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