2011-09-23 18 views
12

(नोट: इस सवाल का पूर्वप्रक्रमक hackery साथ आने के लिए इस दूसरे सवाल का जवाब देने को नो-सेशन आवंटन उत्पन्न करने के लिए कोशिश कर रहा से प्रेरित हुआ:क्या यह एक ही पते पर प्लेसमेंट के लिए अच्छी तरह से परिभाषित/कानूनी है?

Macro that accept new object

... इसलिए सहन कि मन में)

class foo { 
private: 
    int bar; 
public: 
    foo(int bar) : bar (bar) 
     { std::cout << "construct foo #" << bar << std::endl; } 
    ~foo() 
     { std::cout << "destruct foo #" << bar << std::endl; } 
}; 

... जो मैं इस तरह आवंटित करेगा:

यहाँ एक काल्पनिक वर्ग है

// Note: for alignment, don't use char* buffer with new char[sizeof(foo)] ! 
void* buffer = operator new(sizeof(foo)); 

foo* p1 = new (buffer) foo(1); 
foo* p2 = new (buffer) foo(2); 

/* p1->~foo(); */ /* not necessary per spec and problematic in gen. case */ 
p2->~foo(); 

जीसीसी मैं चारों ओर मिल गया है, मैं "उम्मीद" परिणाम प्राप्त:

construct foo #1 
construct foo #2 
destruct foo #2 

कौन महान है, लेकिन संकलक/क्रम एक दुरुपयोग के रूप में इस अस्वीकार और अभी भी हो सकता है कल्पना के दाहिने तरफ?

थ्रेडिंग के साथ कैसे? अगर हम वास्तव में इस वर्ग की सामग्री की परवाह नहीं करते हैं (मान लीजिए कि यह सिर्फ एक डमी ऑब्जेक्ट है) क्या कम से कम क्रैश नहीं होगा, जैसे कि सरल एप्लिकेशन में जो इसे पीओडी int के साथ प्रेरित करता है?

+0

मुझे पूरा यकीन है (लेकिन संदर्भ नहीं हैं) कि यह गैर-पीओडी वस्तुओं के लिए कोशेर नहीं है। पीओडी के बारे में निश्चित नहीं है ... – bdonlan

+0

मुझे लगता है कि आपका मतलब है "foo * p1 = new (buffer) foo (1);" –

+0

आपका विनाशक वस्तु की स्थिति को नहीं बदलता है। अधिकांश विनाशक इस तरह नहीं हैं। –

उत्तर

14

पेपरिंग नियुक्ति-नया स्मृति के उसी ब्लॉक पर कई बार बिल्कुल ठीक है। इसके अलावा, हालांकि यह अजीब लग सकता है, आपको उस वस्तु को नष्ट करने की भी आवश्यकता नहीं है जो पहले से ही उस स्मृति में रहता है (यदि कोई है)। मानक स्पष्ट रूप से 3,8/4

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

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

हालांकि, उसी कोड पर विनाशक को दो बार आपके कोड में करने की अनुमति नहीं है। एक बार जब आप स्मृति के उसी क्षेत्र में दूसरी वस्तु बनाते हैं, तो आपने प्रभावी रूप से पहली वस्तु के जीवनकाल को समाप्त कर दिया (भले ही आपने कभी विनाशक नहीं कहा)। अब आपको केवल दूसरी वस्तु को नष्ट करने की आवश्यकता है।

+0

कूल। मैंने इस सवाल पर ध्यान केंद्रित करने के लिए पहला विनाशक लिया कि मुझे इसमें क्या रूचि थी। धन्यवाद! – HostileFork

+0

वाह! आपके उद्धरण की आखिरी पंक्ति के अंतिम भाग की अस्पष्टता मुझे थोड़ा डराता है - "कोई भी प्रोग्राम जो विनाशक द्वारा उत्पादित दुष्प्रभावों पर निर्भर करता है, वह व्यवहार को अपरिभाषित करता है"। विशेष रूप से इस संदर्भ में "पर निर्भर करता है" क्या मतलब है? –

+0

@ माइकल एंडरसन: मैंने इसे उद्धरण से हटा दिया है क्योंकि इस सवाल के लिए अप्रासंगिक है (या तो यह मुझे लग रहा था)। लेकिन मुझे बिल्कुल यकीन नहीं है कि इसका मतलब क्या है। – AnT

2
foo* p1 = new (buffer) foo(1); 
foo* p2 = new (buffer) foo(2); 
p1->~foo(); 
p2->~foo(); 

आप एक ही वस्तु को दो बार नष्ट कर रहे हैं, और वह अकेला अपरिभाषित व्यवहार है। जब आप ऐसा करते हैं तो आपका कार्यान्वयन पिज्जा को ऑर्डर करने का निर्णय ले सकता है, और यह अभी भी spec के दाहिने तरफ होगा।

फिर यह तथ्य है कि आपके बफर को प्रकार के foo की ऑब्जेक्ट को ठीक करने के लिए ठीक से गठबंधन नहीं किया जा सकता है, जो कि फिर से गैर मानक सी ++ है (सी ++ 03 के अनुसार, मुझे लगता है कि सी ++ 11 इसे आराम देता है)।

अद्यतन: सवाल शीर्षक में निर्दिष्ट के बारे में,

यह एक ही पते पर स्थान-नए कई बार करने के लिए कानूनी अच्छी तरह से परिभाषित/है?

हां, क्या यह उसी पते पर नियुक्ति-नए कई बार अच्छी तरह से परिभाषित किया गया है, बशर्ते कि यह कच्ची मेमोरी को इंगित करे।

+0

आप पिज्जा को ऑर्डर करने का हमेशा उल्लेख कैसे करते हैं? :) आप बहुत से लोगों को भूखे लगते हैं। –

+0

प्रश्नकर्ता अभी भी विनाशक कॉल के बिना भी प्रासंगिक है, क्योंकि उन्हें कॉल करने के लिए कोई तकनीकी आवश्यकता नहीं है। मैं जाहिर तौर पर संबंधित बिंदुओं के 'भाषा-वकील' सबूत-से-स्पेक की तलाश में हूं। :) – HostileFork

+0

ऑर्डरिंग पिज्जा उस मामले में आमतौर पर जो करता है उससे कहीं अधिक उत्पादक आउटपुट होगा। मैं सिग्नल हैंडलर और/या ओएस समर्थन की आवश्यकता देखना चाहता हूं क्योंकि यह इस ईंधन प्रणाली Icing अवरोधक को जोड़ने के लिए एक शानदार विशेषता होगी जिसे हम विकसित कर रहे हैं। हमने अब तक अधिकांश डिस्क ऑपरेटिंग सिस्टम में shoehorn करने में कामयाब रहे हैं .... –

0

नहीं - यह सही नहीं दिखता है।

जब आप प्लेसमेंट new का उपयोग करते हैं, तो ऑब्जेक्ट पर आपके द्वारा भेजे गए पते का निर्माण किया जाएगा। इस उदाहरण में आप एक ही पते को पार कर रहे हैं (यानी & बफर [0]) दो बार, इसलिए दूसरी वस्तु केवल पहले ऑब्जेक्ट को समाप्त कर रही है जो पहले से ही इस स्थान पर बनाई गई है।

संपादित करें: मुझे नहीं लगता कि मैं समझता हूं कि आप क्या करने की कोशिश कर रहे हैं।

आप एक सामान्य ऑब्जेक्ट प्रकार है (कि गैर तुच्छ ctor हो सकता है/dtor कि पुनःआवंटन संसाधनों का आवंटन हो सकता है/है) और यदि आप प्लेसमेंट new द्वारा पहली वस्तु मिटा 'बुला स्पष्ट रूप से पहले यह नाशक है बिना यह के शीर्ष पर ing , यह कम से कम एक स्मृति रिसाव होगा।

+0

प्रेरक उदाहरण देखें, और थ्रेडिंग पर विचार करें: http://stackoverflow.com/questions/7522949/c-macro-that-accent-new-object/7523078#7523078 – HostileFork

+0

@ होस्टाइलफ़र्क: अपने संपादन को फिर से पढ़ना मुझे लगता है कि आपकी ऑब्जेक्ट प्रकार हमेशा तुच्छ होगा - इसलिए "विस्मरण" चिंताओं प्रासंगिक नहीं हो सकता है ... –

+0

स्वीकृत उत्तर देखें। डबल विनाशक कॉल की तरह लगता है समस्याओं का कारण बन सकता है, लेकिन प्रतिबिंब ठीक है प्रति spec।प्लेसमेंट नया उन अजीब चीजों में से एक है जो मुझे लगता है कि संकलक इसके लिए आपका शब्द लेगा! – HostileFork