क्या तुच्छ वस्तु के लिए प्लेसमेंट को 'इस' पर नया कहना सुरक्षित है?


20

मुझे पता है कि यह सवाल कई बार पहले ही पूछा जा चुका था लेकिन मुझे इस विशेष मामले का जवाब नहीं मिला।

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

मैं deInitहाथ से लिखने की विधि के बिना इस तरह के वर्ग को फिर से शुरू और ऑब्जेक्ट करना चाहता हूं । क्या ऐसा करना सुरक्षित है?

void A::deInit()
{
  new (this)A{};
}

मैं इसके साथ कोई समस्या नहीं देख सकता - ऑब्जेक्ट हमेशा मान्य स्थिति में है, फिर thisभी उसी पते पर इंगित करता है; लेकिन यह C ++ है इसलिए मैं निश्चित होना चाहता हूं।


2
ऑब्जेक्ट का कोई सदस्य हैं?
नाथनऑलिवर

2
यदि यह मान्य है, तो क्या यह इसके बराबर होगा *this = A{};?
केविन

2
@Amomum का *this = A{};अर्थ है, this->operator=(A{});अर्थात एक अस्थायी ऑब्जेक्ट बनाएं और इसे *thisअस्थायी डेटा के मूल्यों के साथ सभी डेटा सदस्यों के मूल्यों को बदलने के लिए असाइन करें । चूँकि आप जो चाहते हैं और (मेरी राय में) प्लेसमेंट नए की तुलना में अधिक पठनीय है, मैं इसके बजाय उसके साथ जाऊँगा।
केविन

1
@ केविन ओह, मेरा बुरा, तुम सही कह रहे हो। थन - मुझे लगता है कि नकल बराबर होने पर यह बराबर होना चाहिए?
अमोमम

1
कक्षा को शब्दों में समझाने के बजाय, पूरी कक्षा लिखना बेहतर है, और केवल एक विधि नहीं। sscce.org
Bћовић

जवाबों:


17

इसी तरह की वैधानिकता के लिए delete this, thisजहां तक ​​मुझे पता है , प्लेसमेंट नया भी अनुमति है। इसके अलावा, इसके बारे में this, या अन्य पूर्व-मौजूदा संकेत / संदर्भ बाद में उपयोग किए जा सकते हैं, कुछ प्रतिबंध हैं:

[Basic.life]

यदि, किसी वस्तु का जीवनकाल समाप्त हो गया है और भंडारण से पहले जिस वस्तु पर कब्जा कर लिया गया है, उसका पुन: उपयोग या विमोचन किया जाता है, भंडारण स्थान पर एक नई वस्तु बनाई जाती है, जिस पर मूल वस्तु का कब्जा होता है, एक संकेतक जो मूल वस्तु की ओर इशारा करता है, एक संदर्भ मूल वस्तु के लिए संदर्भित, या मूल वस्तु का नाम स्वचालित रूप से नई वस्तु को संदर्भित करेगा और, एक बार जब नई वस्तु का जीवनकाल शुरू हो गया है, तो इसका उपयोग नई वस्तु में हेरफेर करने के लिए किया जा सकता है, यदि:

  • नई ऑब्जेक्ट के लिए संग्रहण वास्तव में उस संग्रहण स्थान को ओवरले करता है जिस पर मूल ऑब्जेक्ट का कब्जा है, और
  • नई वस्तु मूल वस्तु (शीर्ष स्तर के cv-क्वालीफायर की अनदेखी) के समान प्रकार की है, और
  • मूल वस्तु का प्रकार कॉन्स्टेबल-योग्य नहीं है, और, यदि एक वर्ग प्रकार, में कोई गैर-स्थैतिक डेटा सदस्य नहीं है, जिसका प्रकार कॉन्स्ट-योग्य या एक संदर्भ प्रकार है, और
  • न तो मूल वस्तु और न ही नई वस्तु एक संभावित अतिव्यापी उप-विषय ([intro.object]) है।

इस उदाहरण में पहले दो संतुष्ट हैं, लेकिन अंतिम दो को ध्यान में रखना होगा।

तीसरे बिंदु के संबंध में, यह देखते हुए कि फ़ंक्शन गैर-कॉन्स्टेबल-योग्य है, यह मान लेना काफी सुरक्षित होना चाहिए कि मूल ऑब्जेक्ट नॉन-कॉस्ट है। यदि कॉलर को हटा दिया गया है तो गलती कॉलर की तरफ है। कॉन्स्टेबल / रेफरेंस मेंबर के बारे में, मुझे लगता है कि यह जाँच कर बताया जा सकता है कि यह असाइन करने योग्य है:

static_assert(std::is_trivial_v<A> && std::is_copy_assignable_v<A>);

बेशक, चूंकि असाइनमेंट एक आवश्यकता है, आप इसके बजाय बस उपयोग कर सकते हैं *this = {};जो मैं उसी कार्यक्रम का उत्पादन करने की उम्मीद करूंगा। एक और अधिक दिलचस्प उपयोग का मामला *thisकिसी अन्य प्रकार की वस्तु के लिए मेमोरी का पुन: उपयोग करने के लिए हो सकता है (जो उपयोग करने के लिए आवश्यकताओं को विफल कर देगा this, कम से कम रीइन्टरप्रिटिंग + लॉंडरिंग के बिना)।

delete thisप्लेसमेंट नए के समान , thisशायद ही "सुरक्षित" के रूप में वर्णित किया जा सकता है।


दिलचस्प। क्या यह सुनिश्चित करना संभव है कि इस प्रकार की सभी स्थितियाँ कुछ प्रकार के लक्षणों पर static_assert से संतुष्ट हैं? यकीन नहीं होता कि अगर
कांस्ट

1
@Amomum मुझे नहीं लगता कि सब -जेक्ट होना एक ऐसी चीज है जिसका परीक्षण किया जा सकता है। कॉन्स्ट या रेफरेंस सदस्य वर्ग को गैर-असाइन करने योग्य बनाते हैं, जो मुझे नहीं लगता कि एक तुच्छ वर्ग के लिए अन्यथा हो सकता है।
एरोरिका

इसका मतलब यह है कि सख्ती-अलियासिंग कब्ज के संबंध में आती है? क्या आप एक उदाहरण प्रदान कर सकते हैं जहां यह खेल में आ सकता है?

1
@darune इस पर एक कास्ट ऑब्जेक्ट, प्लेसमेंट-नया बनाएं, ऑब्जेक्ट के मूल नाम (या पहले से मौजूद पॉइंटर या रेफरेंस) का उपयोग करें और व्यवहार अपरिभाषित होगा। बहुत ही प्रभावी रूप से सख्त अलियासिंग ऑप्टिमाइज़ेशन के रूप में एक ही है, अगर पूरी तरह से एक ही नहीं।
एरोरिका

1
का विलोम delete ptrहै new T()। का विलोम new(ptr)T{}है ptr->~T();stackoverflow.com/a/8918942/845092
डक

7

इसे कवर करने वाले नियम [basic.life] / 5 में हैं

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

और [basic.life] / 8

यदि, किसी वस्तु का जीवनकाल समाप्त हो गया है और भंडारण से पहले जिस वस्तु पर कब्जा कर लिया गया है, उसका पुन: उपयोग या विमोचन किया जाता है, भंडारण स्थान पर एक नई वस्तु बनाई जाती है, जिस पर मूल वस्तु का कब्जा होता है, एक संकेतक जो मूल वस्तु की ओर इशारा करता है, एक संदर्भ मूल वस्तु के लिए संदर्भित, या मूल वस्तु का नाम स्वचालित रूप से नई वस्तु को संदर्भित करेगा और, एक बार जब नई वस्तु का जीवनकाल शुरू हो गया है, तो इसका उपयोग नई वस्तु में हेरफेर करने के लिए किया जा सकता है, यदि:

  • नई ऑब्जेक्ट के लिए संग्रहण वास्तव में उस संग्रहण स्थान को ओवरले करता है जिस पर मूल ऑब्जेक्ट का कब्जा है, और

  • नई वस्तु मूल वस्तु (शीर्ष स्तर के cv-क्वालीफायर की अनदेखी) के समान प्रकार की है, और

  • मूल वस्तु का प्रकार कॉन्स्टेबल-योग्य नहीं है, और, यदि एक वर्ग प्रकार, में कोई गैर-स्थैतिक डेटा सदस्य नहीं है, जिसका प्रकार कॉन्स्ट-योग्य या एक संदर्भ प्रकार है, और

  • न तो मूल वस्तु और न ही नई वस्तु एक संभावित अतिव्यापी उप-विषय ([intro.object]) है।

चूंकि आपकी वस्तु तुच्छ है, इसलिए आपको [basic.life] / 5 के बारे में चिंता करने की आवश्यकता नहीं है और जब तक आप [basic.life] / 8 से बुलेट बिंदुओं को संतुष्ट करते हैं, तब तक यह सुरक्षित है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.