2010-01-29 13 views
45

पुन: प्रारंभ करने के लिए एक कन्स्ट्रक्टर को कॉल करना क्या इसके कन्स्ट्रक्टर का उपयोग करके कक्षा के किसी ऑब्जेक्ट को फिर से शुरू करना संभव है?ऑब्जेक्ट

+1

पुनः आरंभ करने से आपका क्या मतलब है? – David

+0

वेरिएबल्स को समान मान देते हैं जब उन्हें पहले बनाया गया था। – cpx

+0

नील का समाधान "सर्वोत्तम" है, हालांकि आपके डिज़ाइन को फ़िक्सिंग की आवश्यकता है। – GManNickG

उत्तर

56

की क्रमबद्ध करें। एक वर्ग एक को देखते हुए:

A a; 
... 
a = A(); 

पिछले बयान initialisation नहीं है, यह काम है, लेकिन यह शायद तुम क्या चाहते है।

+9

+1 बेशक इसे एक पूर्ण, सही असाइनमेंट ऑपरेटर लिखने की भी आवश्यकता है। –

+15

@ ग्रेग के लिए यह एक सही असाइनमेंट ऑपरेटर है, जो आवश्यक रूप से लिखना आवश्यक नहीं है - डिफ़ॉल्ट अक्सर पूरी तरह से ठीक होगा। –

+0

यदि '''' को' नया 'कीवर्ड का उपयोग करके तत्काल किया गया तो क्या यह संसाधन रिसाव का कारण बन जाएगा? – davidhood2

10

नहीं, कन्स्ट्रक्टर केवल तभी बुलाए जाते हैं जब ऑब्जेक्ट पहली बार बनाया जाता है। इसके बजाय इसे करने के लिए एक नई विधि लिखें।

संपादित

मैं नियुक्ति नई स्वीकार नहीं करेगा, क्योंकि मैं काम के लिए एक पालतू जानवर रैप्टर प्राप्त करने के लिए नहीं करना चाहती।

See this comic, लेकिन हाथ पर विषय के बारे में सोच ...

9

लघु जवाब:

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

class C1 { 
public: 
    C1(int p1, int p2) { 
    Init(p1,p2); 
    } 
    void Init(int p1, int p2) { ... } 
}; 

Nitpicker कोने:

वहाँ कुछ अविश्वसनीय रूप से बुराई एक वस्तु के बाद C++ में एक निर्माता कॉल करने के लिए बनाई गई है रास्ता नहीं है? लगभग निश्चित रूप से, यह सब के बाद सी ++ है। लेकिन यह मूल रूप से बुराई है और इसका व्यवहार लगभग निश्चित रूप से मानक द्वारा परिभाषित नहीं किया गया है और इससे बचा जाना चाहिए।

+2

आप कर सकते थे: 'टी एक्स; x-> ~ टी(); नया (और एक्स) टी(); 'मुझे यकीन नहीं है कि यह कैसे परिभाषित किया गया है, यह लगभग ठीक लगता है। (ठीक है कानूनी रूप में, ठीक नहीं है क्योंकि इसमें पूरी तरह से भयानक कोड है।) – GManNickG

+4

@GMan, जब मैंने इसे पढ़ा तो मुझे स्पष्ट रूप से shuddered :) – JaredPar

27

यह संभव है, हालांकि यह एक बहुत बुरा विचार है। कारण यह है कि मौजूदा वस्तु पर विनाशकों को बुलाए बिना, आप संसाधनों को रिसाव करने जा रहे हैं।

उस प्रमुख चेतावनी के साथ, यदि आप इसे करने पर जोर देते हैं, तो आप प्लेसमेंट का उपयोग कर सकते हैं।

// Construct the class 
CLASS cl(args); 

// And reconstruct it... 
new (&cl) CLASS(args); 
+5

आपको इसे किसी को सुझाव देने के लिए केवल -1 प्राप्त करना चाहिए: पी, लेकिन एक +1 हैक के लिए - यह नहीं पता था, इसलिए कुल –

+7

में 0 0 'प्ले-> ~ क्लास();' प्लेसमेंट से पहले, जैसा कि मैंने जेरेड के जवाब पर कहा था। मुझे यकीन नहीं है कि यह परिभाषित है, कानूनी लगता है। – GManNickG

+2

+1, केवल सही समाधान। बुराई नहीं, यह तरीका है कि यह कैसे किया जाता है। –

38

सचमुच? हां, प्लेसमेंट का उपयोग करके नया। लेकिन सबसे पहले आपको पहले निर्मित वस्तु को नष्ट करना होगा।

SomeClass object(1, 2, 3); 
... 
object.~SomeClass(); // destruct 
new(&object) SomeClass(4, 5, 6); // reconstruct 
... 
// Final destruction will be done implicitly 

हालांकि इसका मूल्य पूरी तरह से सैद्धांतिक से परे नहीं जाता है। अभ्यास में ऐसा मत करो। पूरी बात विवरण से परे बदसूरत है।

+13

क्या आप समझा सकते हैं कि आप क्यों मानते हैं कि यह "विवरण से बदसूरत" है? ऐसा लगता है कि यह कोड डुप्लिकेशंस और बग्स से बचने में एक वैध उपयोग है जो एक 'स्पष्ट' विधि को एक निर्माता और विनाशक से अलग करता है। –

+3

क्या बनाता है यह "बदसूरत" यह है कि 'ऑब्जेक्ट' पर विनाशक को बुलाए जाने के बाद, आपके पास एक अनियंत्रित स्टैक वैरिएबल है। इस बिंदु के बाद 'ऑब्जेक्ट' के साथ कुछ भी करने की कोशिश करना असुरक्षित है। यहां तक ​​कि कोई तरीका नहीं है तकनीक कि ऑब्जेक्ट बाद में नष्ट कर दिया गया है। लेकिन एक बार पुनर्निर्माण के बाद, यह फिर से वैध है। मैं तब तक कहूंगा जब तक कि दो पंक्तियां पीछे-पीछे हों, यह सुरक्षित है। –

+0

ईमानदारी से, मैं इसे किसी भी प्रकार के वर्ड टेम्पलेट फ़ंक्शन या यहां तक ​​कि केवल एक मैक्रो में डाल सकता हूं, यह स्पष्ट करने के लिए कि क्या हो रहा है और दो कथनों के बीच कोड को गलती से डालने से रोकने के लिए। – LivePastTheEnd

1

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

उदाहरण के लिए, अगर आप इस तरह एक खेल नहीं लिखा होगा:

void play_level(level_number, level_data) { 
    Player player; //gets "re-initialized" at the beginning of each level using constructor 
    //code for level 
} 

void game() { 
    level_number = 1; 
    while (some_condition) { 
     play_level(level_number, level_data); 
     ++level_number; 
    } 
} 

(बहुत किसी न किसी रूपरेखा विचार व्यक्त करने के लिए, करने के लिए नहीं:

initialize player 
code for level 1 
... 
reinitialize player 
code for level 2 
... 
etc 

इसके बजाय आप के लिए प्रयास करता हूँ दूरस्थ रूप से संकलित हो।)

6

हाँ आप धोखा दे सकते हैं और प्लेसमेंट का उपयोग कर सकते हैं।
नोट: मैं इस सलाह नहीं:

#include <new> 

reInitAnA(A& value) 
{ 
    value.~A();   // destroy the old one first. 
    new (&value) A();  // Call the constructor 
          // uses placement new to construct the new object 
          // in the old values location. 
} 
+0

क्या नया विफल रहता है? – Jagannath

+1

इस मामले में नया असफल नहीं हो सकता है (स्मृति आवंटन के मामले में) क्योंकि कोई स्मृति आवंटित नहीं की जाती है। कन्स्ट्रक्टर असफल हो सकता है और जैसे ही आप उम्मीद करेंगे अपवाद फेंक सकते हैं। –

+0

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

1
destructing के बजाय

और जैसा कि ऊपर कुछ उत्तर ने सुझाव दिया reinitializing, यह नीचे की तरह एक काम करने के लिए बेहतर है। नीचे दिया गया कोड अपवाद सुरक्षित है।

T& reinitialize(int x, int y) 
    { 
     T other(x, y); 
     Swap(other); // this can't throw. 
     return *this; 
    } 
7

सी ++ 11 में, आप यह कर सकते हैं:

#include <type_traits> 

template <class T, typename... Args> 
void Reconstruct(T& x, Args&&... args) 
{ 
    static_assert(!std::has_virtual_destructor<T>::value, "Unsafe"); 
    x.~T(); 
    new (&x) T(std::forward<Args>(args)...); 
} 

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

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

2

मैं आमतौर पर आधुनिक C++ निम्नलिखित लिखें:

SomeClass a; 
... 
a = decltype(a)(); 

यह नहीं सबसे प्रभावी तरीका है, के रूप में यह प्रभावी रूप से a के एक ही प्रकार का एक और वस्तु निर्माण करती है और a करने के लिए इसे प्रदान करती है हो सकता है, लेकिन यह काम करता है ज्यादातर मामलों में, आपको a के प्रकार को याद रखने की आवश्यकता नहीं है, और यदि टाइप बदलता है तो यह अनुकूल होता है।

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