2011-09-12 28 views
12

मैं हाल ही में प्रबंधित पॉइंटर्स सीख रहा हूं और निम्नलिखित परिदृश्य में भाग गया हूं।सी ++ स्टैक ऑब्जेक्ट के साझा_ptr

मैं गेम व्यू के लिए मॉडल/नियंत्रक वर्ग को कार्यान्वित कर रहा हूं। मेरा विचार, मॉडल में चीजें प्रस्तुत करेगा। बहुत सीधा। मेरा मुख्य समारोह में, मैं सभी तीन इस तरह का दृष्टांत:

RenderModel m; 
m.AddItem(rect); // rect gets added just fine, it's an "entity" derivee 
RenderView v; 
v.SetModel(m); 

मेरे विचार वर्ग प्रस्तुत करना बिल्कुल स्पष्ट है:

class RenderView 
{ 
public: 
explicit RenderView(); 
~RenderView(); 

void Update(); 

void SetModel(RenderModel& model); 

private: 
// disable 
RenderView(const RenderView& other); 
RenderView& operator=(const RenderView& other); 

// private members 
boost::scoped_ptr<RenderModel> _model; 
}; 

setview के लिए कार्यान्वयन सुंदर मानक है:

void RenderView::SetModel(RenderModel& model) 
{ 
    _model.reset(&model); 
} 

इसकी कुंजी यह है कि दृश्य एक स्मार्ट सूचक में एक मॉडल स्टोर करता है। हालांकि मुख्य रूप से, मॉडल को ढेर पर आवंटित किया गया था। जब प्रोग्राम निकलता है, तो स्मृति दो बार हटा दी जाती है। यह समझ में आता है। मेरी वर्तमान समझ मुझे बताती है कि जो कुछ भी smart_ptr (किसी भी तरह का) में संग्रहीत हो जाता है उसे ढेर पर आवंटित नहीं किया जाना चाहिए था।

उपर्युक्त सेटअप के बाद, मेरा प्रश्न सरल है: मैं कैसे निर्देश दे सकता हूं कि ढेर पर पैरामीटर आवंटित नहीं किया गया था? एक पैरामीटर के रूप में एकमात्र समाधान के रूप में एक स्मार्ट सूचक स्वीकार कर रहा है? फिर भी मुझे लगता है कि किसी को यह सुनिश्चित नहीं कर सकता है मेरे विचार वर्ग का उपयोग कर के रूप में कुछ गलत नहीं कर सका:

// If I implemented SetModel this way: 
void RenderView::SetModel(const std::shared_ptr<RenderModel>& model) 
{ 
    _model.reset(&*model); 
} 

RenderModel m; 
RenderView v; 
std::shared_ptr<RenderModel> ptr(&m); // create a shared_ptr from a stack-object. 
v.SetModel(ptr); 

उत्तर

8

मैं कैसे हुक्म है कि एक पैरामीटर ढेर पर आवंटित नहीं किया गया था?

हां, कॉलर को std::shared_ptr<RenderModel> प्रदान करने की आवश्यकता है। यदि कॉलर std::shared_ptr गलत तरीके से गलत करता है, तो वह कॉलर की समस्या है, न कि आपके।

आप एक RenderView के लिए करना चाहते हैं के लिए एक विशेष RenderModel के एकमात्र मालिक होने के लिए, समारोह लेने रखने पर विचार एक std::unique_ptr या std::auto_ptr बजाय; इस तरह यह स्पष्ट है कि कॉलर को फ़ंक्शन कॉल करने के बाद ऑब्जेक्ट के स्वामित्व को बनाए रखना नहीं चाहिए।

वैकल्पिक रूप से, अगर RenderModel कॉपी करने के लिए सस्ता है, यह की एक प्रतिलिपि बनाने और नकल का उपयोग करें:

_model.reset(new RenderModel(model)); 
+0

यदि कॉलर share_ptr को गलत तरीके से नियंत्रित करता है, तो मुझे लगता है कि ऐसा कुछ पता लगाने का कोई तरीका नहीं है? मैं बस पूछता हूं, क्योंकि मुझे लगता है कि मैं फिर से यह गलती कर सकता हूं, और मैं इस मुद्दे को फिर से डिबग करने में कुछ घंटे नहीं बिताना चाहता हूं। मैं अपने मॉनिटर पर अपने चिपकने वाला नोट चिपक सकता हूं जब तक कि यह मेरे सिर में जला नहीं जाता ... – Short

+0

पता लगाने के लिए कुछ ज्ञात 'चाल' हैं कि कोई वस्तु ढेर या ढेर में रहती है, जैसे पते की तुलना करना। इन सभी रिले अपरिभाषित या कार्यान्वयन निर्भर व्यवहार पर। मुझे लगता है कि अगर यह सिर्फ खुद को संकेत दे तो यह काम कर सकता है, लेकिन वे असली समाधान नहीं हैं। –

+3

नहीं, यदि आपका फ़ंक्शन 'std :: shared_ptr' लेता है, तो यह बताने का कोई तरीका नहीं है कि वह सूचक एक मान्य ऑब्जेक्ट को इंगित करता है या नहीं। उस ने कहा, अगर यह स्पष्ट रूप से 'std :: shared_ptr' लेता है, तो स्क्रू अप करना बहुत कठिन होता है (कोड जो स्थानीय चर से 'std :: shared_ptr' बनाता है, पहली नजर में गलत दिखता है और इससे बचना आसान होता है)। –

3

आप शायद अपने वर्ग के शब्दों और अधिक स्पष्ट रूप से परिभाषित करना चाहिए। यदि आप रेंडरव्यू को रेंडरमोडेल के मालिक बनना चाहते हैं तो इसे इसे स्वयं बनाना चाहिए (शायद किसी फैक्टर के साथ उपयोग करने के लिए कन्स्ट्रक्टर में कुछ पहचानकर्ता प्राप्त करें)।

मैंने कक्षाओं को देखा है जो ऑब्जेक्ट्स के स्वामित्व प्राप्त करते हैं, और यह स्पष्ट रूप से परिभाषित किया गया था कि यह ऑब्जेक्ट ढेर पर होना चाहिए, लेकिन यह मेरी राय के लिए, त्रुटि प्रवण है, जैसा कि अब आप की गई त्रुटि की तरह है। आप एक स्मार्ट पॉइंटर को स्टैक ऑब्जेक्ट नहीं दे सकते हैं जो इसे ढेर पर होने की उम्मीद करता है (क्योंकि जब इसे साफ़ करना है तो यह उस पर डिलीट का उपयोग करेगा)।

+0

क्यूटी उपरोक्त मॉडल का उपयोग करता है, यही वह जगह है जहां से मुझे विचार मिला। यह कई मॉडल को एक मॉडल से जोड़ने की अनुमति देता है। मुझे लगता है कि उनके कार्यान्वयन को और अधिक बारीकी से देखना होगा। – Short

2

जिस तरीके से आपने वर्णन किया है कि आप क्या करना चाहते हैं वह पूरी तरह से गलत है। एमवीपी डिजाइन पैटर्न में, दृश्य को सीधे मॉडल तक नहीं पहुंचना चाहिए, लेकिन प्रस्तुतकर्ता को आदेश भेजना चाहिए (प्रस्तुतकर्ता के कार्यों को कॉल करके)।

वैसे भी, अन्य की आपके प्रश्न का उत्तर है: अपने मॉडल वस्तु इस तरह, ढेर पर आवंटित किया जाना है:

std::shared_ptr<RenderModel> ptr(new RenderModel); 
RenderView v; 
v.SetModel(ptr); 

अन्यथा अपने shared_ptr वस्तु एक ढेर वस्तु को हटाने का प्रयास करने जा रहा है।

1

आपको वापस जाना चाहिए और डिजाइन पर विचार करना चाहिए। पहला कोड गंध यह है कि आप संदर्भ द्वारा ऑब्जेक्ट ले रहे हैं और फिर इसे स्मार्ट पॉइंटर के रूप में प्रबंधित करने का प्रयास कर रहे हैं। यह गलत है।

आपको यह तय करके शुरू करना चाहिए कि संसाधन के लिए कौन जिम्मेदार है, और इसके आसपास डिज़ाइन, RenderView संसाधन के प्रबंधन के लिए ज़िम्मेदार है, तो इसे संदर्भ को स्वीकार नहीं करना चाहिए, बल्कि एक (स्मार्ट) पॉइंटर। यदि यह एकमात्र मालिक है, तो हस्ताक्षर को std::unique_ptr (या std::auto_ptr लेना चाहिए यदि आपका कंपाइलर + libs unique_ptr का समर्थन नहीं करता है), यदि स्वामित्व पतला हो जाता है (जब भी संभव हो एकमात्र मालिक बनाना पसंद करते हैं), तो shared_ptr का उपयोग करें।

लेकिन वहाँ भी अन्य परिदृश्यों जहां RenderView बिल्कुल संसाधन का प्रबंधन करने की जरूरत नहीं है, ऐसी स्थिति में यह संदर्भ द्वारा संदर्भ द्वारा मॉडल लेने के लिए और यह स्टोर कर सकते हैं अगर यह RenderView के जीवनकाल के दौरान बदला नहीं जा सकता है। इस परिदृश्य में, जहां RenderView संसाधन के प्रबंधन के लिए ज़िम्मेदार नहीं है, इसे कभी भी delete (स्मार्ट पॉइंटर के माध्यम से) करने का प्रयास नहीं करना चाहिए।

1
class ModelBase 
{ 
    //..... 
}; 

class RenderView 
{ 
    //.......... 
public: 
    template<typename ModelType> 
    shared_ptr<ModelType> CreateModel() { 
     ModelType* tmp=new ModelType(); 
     _model.reset(tmp); 
     return shared_ptr<ModelType>(_model,tmp); 
    } 

    shared_ptr<ModelBase> _model; 
    //...... 
}; 

मॉडल वर्ग निर्मापक मानकों है, यह विधि CreateModel() पैरामीटर जोड़ सकते हैं और सी ++ 11 आदर्श अग्रेषण शब्दावली का उपयोग करना संभव है।

1

आपको उपयोगकर्ता को इनपुट को सही तरीके से पास करने की आवश्यकता होनी चाहिए। सबसे पहले अपने इनपुट प्रकार को एक स्मार्ट सूचक (संदर्भ चर के बजाय) में बदलें। दूसरे ने उन्हें स्मार्ट पॉइंटर को ठीक तरह से पास कर दिया है जो कुछ भी नहीं करता है (नीचे कोई डिलीट नहीं, उदाहरण)।

मेमोरी सेगमेंट की जांच करने के लिए एक हैकिश विधि होगी। स्टैक हमेशा कर्नेल स्पेस से नीचे बढ़ने जा रहा है (मुझे लगता है कि 32 बिट में 0xC0000000, 64 बिट में 0x7fff2507e800 की तरह कुछ, नीचे दिए गए कोड के आधार पर)। तो आप स्मृति स्थान के आधार पर अनुमान लगा सकते हैं कि यह एक स्टैक वैरिएबल है या नहीं। लोग आपको बताएंगे कि यह पोर्टेबल नहीं है, लेकिन यह तब तक है जब तक कि आप एम्बेडेड सिस्टम पर तैनात सामान नहीं ले लेते।

#include <iostream> 
#include <memory> 

using namespace std; 

class foo 
{ 
    public: 
    foo(shared_ptr<int> in) { 
     cerr << in.get() << endl; 
     cerr << var.use_count() << endl; 
     var = in; 
     cerr << var.use_count() << endl; 
    }; 

    shared_ptr<int> var; 
}; 

struct NoDelete { 
    void operator()(int* p) { 
     std::cout << "Not Deleting\n"; 
    }; 
}; 

int main() 
{ 
    int myval = 5; 

    shared_ptr<int> valptr(&myval, NoDelete()); 
    foo staticinst(valptr); 

    shared_ptr<int> dynptr(new int); 
    *dynptr = 5; 
    foo dynamicinst(dynptr); 
} 
0

संक्षेप में: कस्टम डिलीटर परिभाषित करें। ढेर वस्तु पर एक स्मार्ट सूचक के मामले में, आप स्मार्ट सूचक एक कस्टम Deleter साथ, इस मामले में एक "अशक्त Deleter" (या "StackObjectDeleter") में निर्माण कर सकते हैं

class StackObjectDeleter { 
public: 
    void operator() (void*) const {} 
}; 

std::shared_ptr<RenderModel> ptr(&m, StackObjectDeleter()); 

StackObjectDeleter default_delete के रूप में बदल देता है हटाना वस्तु। default_delete बस कॉल को हटाता है (या हटाएं [])। StackObjectDeleter के मामले में, कुछ भी नहीं होगा।

+0

पवित्र नेक्रो बैटमैन! – Short

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

  • कोई संबंधित समस्या नहीं^_^