2009-09-22 11 views
7

मान लीजिए कि मेरे पास RAII-style C++ क्लास है:क्या आरएआईआई-स्टाइल क्लास को "गुमनाम" तत्काल होने से रोकना संभव है?

class StateSaver 
{ 
    public: 
    StateSaver(int i) { saveState(); } 
    ~StateSaver() { restoreState(); } 
}; 

... मेरे कोड में ऐसा करने के लिए उपयोग किया जाना चाहिए:

void Manipulate() 
{ 
    StateSaver save(1); 

    // ...do stuff that modifies state 
} 

... लक्ष्य कुछ राज्य दर्ज करना है, सामान करें , तब उस स्थिति को छोड़ दें जब मैं उस दायरे को छोड़ दूं। क्या इस टाइपो को संकलित नहीं करने का कोई तरीका है (या चेतावनी, या किसी भी तरह शिकायत करें ताकि गलती देखी जा सके)?

void Manipulate() 
{ 
    StateSaver(1); // ruh-roh, state saved and immediately restored! 

    // ...do stuff that modifies state 
} 

मुझे सी ++ में कुछ भी पता नहीं है जिसे मैं इसे रोकने के लिए उपयोग कर सकता हूं, लेकिन इसका मतलब यह नहीं है कि यह अस्तित्व में नहीं है। यदि सी ++ में कुछ भी नहीं है, तो कंपाइलर-विशिष्ट एक्सटेंशन स्वीकार्य होंगे। मैं मुख्य रूप से जीसीसी और एमएसवीसी को लक्षित करने में कुछ भी दिलचस्पी लेता हूं (किसी दिन आईसीसी, अन्य कंपाइलर्स के लिए विचारों का स्वागत है लेकिन उपयोगी होने की संभावना कम है) इसलिए उनमें से किसी के लिए हैक्स उपयोगी होंगे (निश्चित रूप से # ifdef'd मैक्रो परिभाषाओं में उचित रूप से) ।

+0

SaveMatrix(): - मेरे लिए एक समारोह कॉल की तरह> लग रहा है। –

+0

SaveMatrix बचाने(): -> मेरे लिए एक समारोह घोषणा की तरह लग रहा। –

उत्तर

3

मैं वास्तव में संस्करण वाल्डो पोस्ट से तरीके का एक गुच्छा में my solution बदलाव करने की थी, लेकिन मैं क्या अंत में करने के लिए मिल गया है की एक वृहद ized संस्करण है:

class GuardNotifier 
{ 
    bool* notified; 
    public: 
    GuardNotifier() : notified(NULL) { } 
    void init(bool* ptr) { notified = ptr; } 
    ~GuardNotifier() { *notified = true; } 
}; 
class GuardNotifyReceiver 
{ 
    bool notified; 
    public: 
    GuardNotifyReceiver() : notified(false) { } 
    void init(const GuardNotifier& notifier) 
     { const_cast<GuardNotifier&>(notifier).init(&notified); } 
    ~GuardNotifyReceiver() { assert(notified); } 
}; 
class StateSaver 
{ 
    GuardNotifyReceiver receiver; 
    public: 
    StateSaver(int i, 
       const GuardNotifier& notifier = GuardNotifier()) 
    { 
     receiver.init(notifier) 
     saveState(); 
    } 
    ~StateSaver() 
    { 
     restoreState(); 
    } 
}; 
6

SaveMatrix save(); किसी ऑब्जेक्ट को परिभाषित नहीं करता है। यह एक समारोह घोषित करता है।

दूसरों को (या स्वयं, एफटीएम) को कुछ और करने से रोकने के लिए आप बहुत कम कर सकते हैं। केवल एक चीज जिसे मैं सोच सकता हूं वह कोड नहीं लिख रहा है, बल्कि इसके बजाय एक मैक्रो लिख रहा है।

#define SAVE_MATRIX SaveMatrix save ## __LINE__ 

हालांकि, यह काफी बदसूरत है। ओटीओएच, यह संकलन समय पर त्रुटि पकड़ता है।

9

मुझे यकीन नहीं है कि संकलन समय पर कुछ भी किया जा सकता है। एक रन-टाइम की जांच के लिए, आप ऐसा कर सकता है:

struct SaveMatrix 
{ 
    SaveMatrix(const SaveMatrix& that) { 
     assert(this == &that); 
     glPushMatrix(); 
    } 
    ~SaveMatrix() { glPopMatrix(); } 
}; 

किस ग्राहक की आवश्यकता है लिखने के लिए:

SaveMatrix sm(sm); 

और एक अस्थायी के लिए भी ऐसा ही करने का कोई उपाय नहीं एक पहचानकर्ता के लिए यह बाध्यकारी बिना वहाँ (जिस बिंदु पर यह एक ऑटो चर से अलग नहीं है)।

+2

अच्छा एक, थोड़ा शुरुआत में अजीब लगता है, लेकिन आरए II-मुहावरा का हिस्सा बन सकता है, क्योंकि सवाल सी ++/आरए II के साथ एक असली मुद्दा दिखाने करता है। मैं नहीं बल्कि यह जानने कि मेरे ताला इस वजह से काम नहीं किया से अधिक cruft का एक छोटा सा होगा। – stefaanv

+0

हम्म, विकल्पों में से मुझे लगता है मैं इस सबसे ज्यादा पसंद है।यह काफी स्वाभाविक नहीं है, लेकिन फिर, आरएआईआई पूरी तरह से प्राकृतिक नहीं है, कम से कम नहीं, यदि आप मुख्य रूप से कक्षाओं के साथ-साथ प्रारंभिकरण-और-सफाई के रूप में कक्षाओं के बारे में सोचते हैं। धन्यवाद! –

1

वर्ग कभी नहीं बता सकते हैं कि यह के रूप में instantiated गया था एक अस्थायी (SaveMatrix()) या (SaveMatrix बचाने;) एक चर के रूप में। मुझे लगता है कि कर प्रोग्रामर को रोकने के लिए सबसे अच्छा तरीका है कि ढेर या मैक्रो हैक्स निर्माण के बाद एक सदस्य समारोह कॉल, जैसे मजबूर करने के लिए है बिना:

class RAII 
{ 
public: 
    bool valid; 
    RAII() 
     : valid(false) 
    { 
     cout << "RAII ctor" << endl; 
    } 

    void Do() 
    { 
     valid = true; 
    } 

    ~RAII() 
    { 
     assert(valid); 
     cout << "RAII dtor" << endl; 
    } 
}; 

यह तो इस प्रकार काम करता है:

{ 
    // Intended use 
    RAII raii; 
    raii.Do(); 

    cout << "Some task" << endl; 
} 

{ 
    // Woops: forgot Do() 
    RAII raii; 

    cout << "Some task" << endl; 
} 

{ 
    // Woops: forgot Do() 
    RAII(); 

    cout << "Some task" << endl; 
} 

{ 
    // Programmer shot self in foot, hopefully the act of typing this would make them realise that 
    RAII().Do(); 

    cout << "Some task" << endl; 
} 
+1

वह 'RAII()।() 'विफल रहता है यहां कोई समस्या नहीं प्रतीत होती है। AFAIU, ओप मर्फी लड़के को बंद करने की कोशिश करता है, मच्छियाली नहीं। – sbi

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