2009-05-15 13 views
8

क्या निम्न कोड में प्रारंभकर्ता सूची में किसी अन्य ऑब्जेक्ट को 'यह' पास करते समय कोई समस्या है?इसे कन्स्ट्रक्टर प्रारंभकर्ता सूची से पास कर रहा है

class Callback { public: virtual void DoCallback() = 0; }; 

class B 
{ 
    Callback& cb; 
public: 
    B(Callback& callback) : cb(callback) {} 
    void StartThread(); 

    static void Thread() 
    { 
     while (!Shutdown()) 
     { 
      WaitForSomething(); 
      cb.DoCallback(); 
     } 
    } 
}; 

class A : public Callback 
{ 
    B b; 
public: 
    A() : b(*this) {b.StartThread();} 
    void DoCallback() {} 
}; 

यदि ऐसा करने में असुरक्षित है, तो सबसे अच्छा विकल्प क्या है?

उत्तर

10

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

एक सुरक्षित (लेकिन पूरी तरह से सुरक्षित नहीं) विकल्प एक बार कन्स्ट्रक्टर पूरा होने के बाद बी सेट करना है। यह vtable मुद्दों को खत्म नहीं करेगा, लेकिन निर्माण के पहले अन्य सदस्य चरों तक पहुंचने जैसी समस्याओं को हटा देगा।

class A : public Callback { 
    std::auto_ptr<B> spB; 
public: 
    A() { 
    spB.reset(new B(this)); 
    spB->StartThread(); 
    } 
}; 
0

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

6

यदि अन्य वर्ग आपके सूचकांक में केवल सूचक/संदर्भ संग्रहीत करता है, तो यह सुरक्षित है। लेकिन आपको यह सुनिश्चित करना होगा कि this आपके द्वारा A के कन्स्ट्रक्टर खत्म होने से पहले संदर्भित ऑब्जेक्ट तक पहुंचने का प्रयास नहीं कर रहे हैं। A ऑब्जेक्ट अभी तक पूरी तरह से निर्मित नहीं है और A के कॉलिंग विधियों और गुणों तक पहुंचने से अपरिभाषित परिणाम हो सकते हैं।

4

यदि आप बाद में उपयोग के लिए पॉइंटर को संग्रहीत कर रहे हैं तो यह आमतौर पर सुरक्षित है। मैंने यह किया है मैं निम्न कोई भी कार्य नहीं होता:

  • आधार या व्युत्पन्न वर्ग डेटा का उपयोग करने के लिए इसका उपयोग (वे अपने कंस्ट्रक्टर्स न रही हो चलाने)
  • कुछ भी बहुरूपी करते हैं, vtable आरंभ नहीं किया जा सकता है।

Here सी ++ एफएक्यू से एक महान लेख है जो रचनाकारों में "इस" के साथ समस्याओं का विवरण देता है।

+1

तब और अब के बीच कुछ समय, सी ++ पूछे जाने वाले प्रश्न से महान लेख माइग्रेट कर लिया है [यहां] (https: // isocpp .org/wiki/पूछे जाने वाले प्रश्न/ctors # का उपयोग कर-यह-इन-ctors) – peterpi

2

यह पर्याप्त सुरक्षित है, बशर्ते आप ध्यान रखें कि this ऑब्जेक्ट अभी तक पूरी तरह से निर्मित नहीं हुआ है। यदि आपकी B कक्षा केवल निर्माता को संग्रहित करती है, तो कन्स्ट्रक्टर में किसी भी फ़ंक्शन को कॉल किए बिना, आप सुरक्षित हैं। यदि आप बी के कन्स्ट्रक्टर से पॉइंटर तक पहुंचने का प्रयास करते हैं, तो आपको बेहद सावधान रहना होगा और उस क्रम पर ध्यान देना होगा जिसमें ए के सदस्यों को प्रारंभ किया गया है।

3

अभी भी निर्माणाधीन वस्तु में कोड चलाने वाले रचनाकारों में धागे प्रारंभ करना खतरनाक है। आपके द्वारा प्रस्तुत कोड ठीक तरह से काम करेगा, लेकिन समाधान नाजुक है।

यदि DoCallbackA में वर्चुअल विधि को कॉल करता है तो आप अप्रत्याशित परिणामों के साथ समाप्त हो सकते हैं कि थ्रेड कितनी तेजी से चलता है। यदि बुलाया गया तरीका शुद्ध वर्चुअल है तो एप्लिकेशन मर जाएगा, अगर यह शुद्ध नहीं है, तो विधि के A संस्करण को व्युत्पन्न संस्करण के बजाय बुलाया जाएगा। यही कारण है कि आपको कभी भी कन्स्ट्रक्टर से आभासी विधि नहीं बुलानी चाहिए।

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

class Worker 
{ 
public: 
    void DoWork(); 
}; 
void startWorkerThread() 
{ 
    Worker w; // fully create the object that is going to be run before you... 
    boost::thread thr(boost::bind(&Worker::DoWork, &w)); // ...create thread and run 
} 
संबंधित मुद्दे