2013-04-23 10 views
5

का एक अलग व्यवहार कारखाने वर्ग को लागू करते समय मुझे std::auto_ptr का एक व्यवहार सामना करना पड़ा जिसे मैं समझ नहीं पा रहा हूं। मैंने समस्या को निम्न छोटे प्रोग्राम में कम कर दिया, तो ... चलो शुरू करें।सिंगलटन पैटर्न: auto_ptr और unique_ptr

निम्नलिखित सिंगलटन वर्ग पर विचार करें:

singleton.h

#ifndef SINGLETON_H_ 
#define SINGLETON_H_ 

#include<iostream> 
#include<memory> 

class singleton { 
public: 
    static singleton* get() { 
    std::cout << "singleton::get()" << std::endl; 
    if (!ptr_.get()) { 
     std::cout << &ptr_ << std::endl; 
     ptr_.reset(new singleton ); 
     std::cout << "CREATED" << std::endl; 
    } 
    return ptr_.get(); 
    } 

    ~singleton(){ 
    std::cout << "DELETED" << std::endl; 
    } 
private: 
    singleton() {} 
    singleton(const singleton&){} 

    static std::auto_ptr<singleton> ptr_; 
    //static std::unique_ptr<singleton> ptr_; 
}; 

#endif 

singleton.cpp

#include<singleton.h>o 
std::auto_ptr<singleton> singleton::ptr_(0); 
//std::unique_ptr<singleton> singleton::ptr_; 

यहाँ एक स्मार्ट सूचक के उपयोग के संसाधन का प्रबंधन करने में मुख्य रूप से से निर्धारित होता कार्यक्रम से बाहर निकलने पर लीक से बचने की जरूरत है।

a.h

#ifndef A_H_ 
#define A_H_ 

int foo(); 

#endif 

a.cpp

#include<singleton.h> 

namespace { 
    singleton * dummy(singleton::get()); 
} 

int foo() { 
    singleton * pt = singleton::get(); 
    return 0; 
} 

main.cpp

#include<a.h> 

int main() { 

    int a = foo(); 

    return 0; 
} 

अब अजीब हिस्सा: मैं उसके बाद निम्न कार्यक्रम में इस कोड का उपयोग करें। मैं अलग से तीन स्रोतों संकलन:

$ g++ -I./ singleton.cpp -c 
$ g++ -I./ a.cpp -c 
$ g++ -I./ main.cpp -c 

अगर मैं उन्हें स्पष्ट रूप से जोड़ने के इस क्रम में: के रूप में मैं उम्मीद

$ g++ main.o singleton.o a.o 

सब कुछ काम करते हैं, और मैं stdout में निम्नलिखित हो:

singleton::get() 
0x804a0d4 
CREATED 
singleton::get() 
DELETED 

यदि इसके बजाय मैं इस आदेश का उपयोग कर स्रोतों को लिंक करता हूं:

$ g++ a.o main.o singleton.o 

मैं इस उत्पादन प्राप्त करें:

singleton::get() 
0x804a0dc 
CREATED 
singleton::get() 
0x804a0dc 
CREATED 
DELETED 

मैं अलग संकलक ब्रांडों (इंटेल और GNU) और संस्करणों की कोशिश की और इस व्यवहार उन के बीच में संगत है। वैसे भी, मैं कोड नहीं देख पा रहा हूं जिसका व्यवहार लिंकिंग के क्रम पर निर्भर करता है।

इसके अलावा, auto_ptrunique_ptr द्वारा प्रतिस्थापित किया गया है, व्यवहार हमेशा एक सही होने की अपेक्षा के अनुरूप है।

यह मुझे प्रश्न पर लाता है: क्या किसी के पास क्या हो रहा है इस पर कोई संकेत है?

+0

आपका जी ++ संस्करण क्या है? –

+2

शायद आप [इस सवाल] को पढ़ना चाहते हैं (http://stackoverflow.com/questions/86582/)। स्पष्टीकरण के लिए – fredoverflow

उत्तर

4

ऑर्डर जिस पर dummy और std::auto_ptr<singleton> singleton::ptr_(0) का निर्माण किया गया है, निर्दिष्ट नहीं है।

auto_ptr मामले के लिए, यदि आप dummy तो निर्माण singleton::ptr_(0), dummy कॉल में बनाया मूल्य ptr_(0) के निर्माता द्वारा मिटा दिया गया है।

मैं ptr_ के निर्माण के लिए ptr_(([](){ std::cout << "made ptr_\n"; }(),0)); या उस तरह के कुछ के माध्यम से ट्रैकिंग जोड़ता हूं।

तथ्य यह है कि यह unique_ptr के साथ काम करता संयोग है, और संभवतः अनुकूलन के कारण unique_ptr(0) जैसे कुछ नहीं करता है यह पता लगाने की है जिसके तहत कर सकते हैं यह ध्यान केंद्रित किया है, (static डेटा ध्यान केंद्रित किया गया है से पहले निर्माण शुरू होता है, तो संकलक कि unique_ptr(0) यह पता लगाने सकता है अगर बस स्मृति को शून्य करता है, यह कानूनी रूप से कन्स्ट्रक्टर को छोड़ सकता है, जिसका अर्थ है कि अब आप स्मृति को शून्य नहीं करते हैं)।

static std::auto_ptr<singleton>& get_ptr() { 
    static std::auto_ptr<singleton> ptr_(0); 
    return ptr_; 
    } 

और get_ptr() साथ ptr_ के संदर्भ प्रतिस्थापित:

एक तरीका यह तय करने के लिए इस तरह के रूप में, एक विधि उपयोग करने से पहले निर्माण की गारंटी देता है कि उपयोग करने के लिए है।

3

विभिन्न अनुवाद इकाइयों में परिभाषित फ़ाइल-स्कोप ऑब्जेक्ट्स के निर्माण का आदेश अनिर्दिष्ट है। हालांकि, आम तौर पर, दूसरी अनुवाद इकाई में परिभाषित वस्तुओं से पहले एक अनुवाद इकाई में परिभाषित ऑब्जेक्ट्स को परिभाषित किया जाता है। यहां अंतर वह क्रम है जिसमें a.o और singleton.o जुड़े हुए हैं। singleton.oa.o से पहले जुड़ा हुआ है, singleton::ptr_dummy से पहले प्रारंभ हो जाता है और सब ठीक है।जब a.o पहले लिंक किया गया है, dummy पहले प्रारंभ होता है, जो सिंगलटन को बनाता है; तो singleton::ptr_ को singleton की मूल प्रतिलिपि पर पॉइंटर को फेंकने के लिए 0 से प्रारंभ किया जाता है। फिर foo पर कॉल में, singleton::get() पर कॉल सिंगलटन को फिर से बनाता है।

+0

बहुत धन्यवाद। मुझे खेद है कि मैं दो उत्तरों को स्वीकार नहीं कर सकता ... – Massimiliano

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