2016-01-04 11 views
8

मेरे पास एक ही स्थिर सदस्य फ़ंक्शन के दो संस्करण हैं: कोई पॉइंटर-टू-कॉन्स्ट पैरामीटर लेता है और यह पॉइंटर-टू-गैर-कॉन्स्ट पैरामीटर लेता है। मैं कोड डुप्लिकेशन से बचना चाहता हूं।
कुछ ढेर अतिप्रवाह सवाल पढ़ने के बाद (इन सभी के बारे में गैर स्थिर सदस्य कार्यों हालांकि थे) मैं इस के साथ आया था:* स्थिर * सदस्य कार्यों का कॉन्स और गैर-कॉन्स संस्करण

class C { 
private: 
    static const type* func(const type* x) { 
    //long code 
    } 

    static type* func(type* x) { 
     return const_cast<type*>(func(static_cast<const type*>(x))); 
    } 
public: 
    //some code that uses these functions 
}; 

(मैं संकेत के साथ जूझ पता आम तौर पर एक बुरा विचार है, लेकिन मैं डेटा संरचना को लागू करने m)

मैं libstdC++ कि इस तरह दिखता है में कुछ कोड मिला:।
नोट: इन सदस्य कार्यों नहीं हैं

static type* local_func(type* x) 
{ 
    //long code 
} 

type* func(type* x) 
{ 
    return local_func(x); 
} 

const type* func(const type* x) 
{ 
    return local_func(const_cast<type*>(x)); 
} 

पहले दृष्टिकोण में कोड एक फ़ंक्शन में है जो पॉइंटर-टू-कॉन्स्ट पैरामीटर लेता है।
दूसरे दृष्टिकोण में कोड एक फ़ंक्शन में है जो पॉइंटर-टू-गैर-कॉन्स्ट पैरामीटर लेता है।
आम तौर पर किस दृष्टिकोण का उपयोग किया जाना चाहिए? क्या दोनों सही हैं?

+6

शब्दावली सही प्राप्त करें। स्टेटिक क्लास के सदस्य ** ** नहीं हो सकते हैं। – SergeyA

+0

आप कोड डुप्लिकेशंस से बचने के लिए टेम्पलेट का भी उपयोग कर सकते हैं, हालांकि अगर टाइप टाइप हार्डकोड हो तो ओवरकिल हो सकता है। – Manik

+2

@ सर्गेय मैंने लिखा "(इस से मेरा मतलब है कि वे पॉइंटर्स को कॉन्स/गैर-कॉन्स ऑब्जेक्ट्स पर लेते हैं और वापस लौटाते हैं)" – Xack

उत्तर

1

सबसे महत्वपूर्ण नियम यह है कि एक इंटरफेस फ़ंक्शन (सार्वजनिक विधि, एक विस्तार नामस्थान में एक के अलावा एक मुक्त फ़ंक्शन इत्यादि), को इसके इनपुट की स्थिरता को दूर नहीं करना चाहिए। स्कॉट मेयेर पहले const_cast का उपयोग कर दोहराव को रोकने के बारे में बात करने के लिए में से एक था, यहाँ एक विशिष्ट उदाहरण (How do I remove code duplication between similar const and non-const member functions?) है:

struct C { 
    const char & get() const { 
    return c; 
    } 
    char & get() { 
    return const_cast<char &>(static_cast<const C &>(*this).get()); 
    } 
    char c; 

};

यह स्थैतिक/मुक्त कार्यों की बजाय उदाहरण विधियों को संदर्भित करता है, लेकिन सिद्धांत समान है। आप देखते हैं कि गैर-कॉन्स संस्करण अन्य विधि को कॉल करने के लिए कॉन्स्ट जोड़ता है (उदाहरण विधि के लिए, this पॉइंटर इनपुट है)। यह अंत में स्थिरता को दूर करता है; यह सुरक्षित है क्योंकि यह जानता है कि मूल इनपुट नहीं था।

इस तरह के अन्य तरीकों को कार्यान्वित करना अत्यंत खतरनाक होगा। यदि आप दूर आपके द्वारा प्राप्त किए गए फ़ंक्शन पैरामीटर की स्थिरता डाले हैं, तो यदि आप को पारित ऑब्जेक्ट वास्तव में स्थिर है तो आप यूबी में एक बड़ा जोखिम ले रहे हैं। अर्थात, अगर आप किसी भी तरीके कि वास्तव में वस्तु (जो अब है कि आप दूर constness डाली गया है दुर्घटना से ऐसा करने के लिए बहुत आसान है) उत्परिवर्तित फोन, आप आसानी से यूबी प्राप्त कर सकते हैं:

सी ++ मानक, § 5.2 अनुभाग। 11/7 [स्थिरांक डाली]

[नोट: वस्तु, सूचक, lvalue या डेटा सदस्य के लिए सूचक एक const_cast कि दूर डाले एक स्थिरांक-क्वालीफायर अपरिभाषित का उत्पादन हो सकता से उत्पन्न के माध्यम से एक लिखने आपरेशन के प्रकार पर निर्भर व्यवहार। -जेंड नोट]

यह निजी तरीकों/कार्यान्वयन कार्यों में उतना बुरा नहीं है क्योंकि शायद आप ध्यान से नियंत्रित करते हैं कि इसे कैसे/कब बुलाया जाता है, लेकिन यह ऐसा क्यों करता है? लाभ के लिए यह और अधिक खतरनाक है।

संकल्पनात्मक रूप से, यह अक्सर होता है कि जब आपके पास एक ही कार्य का एक कॉन्स और गैर-कॉन्स संस्करण होता है, तो आप ऑब्जेक्ट के आंतरिक संदर्भों के साथ गुजर रहे हैं (vector::operator[] एक कैनोलिक उदाहरण है), और वास्तव में कुछ भी नहीं बदल रहा है, जिसका अर्थ है कि यह सुरक्षित होगा या तो आप इसे लिखेंगे।लेकिन इनपुट की स्थिरता को दूर करना अभी भी और अधिक खतरनाक है; यद्यपि आप इसे स्वयं गड़बड़ करने की संभावना नहीं हो सकते हैं, एक टीम सेटिंग की कल्पना करें जहां आप इसे गलत तरीके से लिखते हैं और यह ठीक काम करता है, और फिर कोई आपको यूबी देने के लिए कुछ को बदलने के लिए कार्यान्वयन को बदलता है।

सारांश में, कई मामलों में यह एक व्यावहारिक अंतर नहीं कर सकता है, लेकिन वहाँ यह करने के लिए एक सही तरीका है कि सख्ती से विकल्प की तुलना में बेहतर है: इनपुट को constness जोड़ने के लिए, और से constness को दूर आउटपुट

+0

"const_cast तुरंत यूबी को आमंत्रित करता है क्योंकि यह एक कॉन्स ऑब्जेक्ट की स्थिरता को दूर करता है" ... नहीं, यह यूबी नहीं है। असल में 'कॉन्स' ऑब्जेक्ट को संशोधित करने का प्रयास करना यूबी है (किसी भी विधि के माध्यम से, 'const_cast' का उपयोग करने के बाद, लेकिन कास्ट स्वयं संशोधन नहीं है)। –

+0

@BenVoigt मेरी गलती, आप सही हैं। मैं उत्सुक हूं, मान लीजिए कि आपके पास इस गैर-कॉन्स्ट पॉइंटर को किसी कॉन्स ऑब्जेक्ट में है। यदि आप अब एक विधि को कॉल करते हैं, तो आपको एक कॉन्स ऑब्जेक्ट पर किसी विधि का गैर-कॉन्स्ट अधिभार प्राप्त होगा। क्या यह स्वचालित रूप से यूबी है? या फिर बदले में यह निर्भर करता है कि विधि क्या करती है? कछुए नीचे सभी तरह से? ;-) –

+0

मुझे विश्वास है कि मैंने जो लिखा है उसकी भावना अभी भी सही है, मैं इसे आपकी सहायता के साथ सटीक सही तकनीकी समर्थन देने के लिए इसे सही करना चाहता हूं। –

0

मैंने वास्तव में पहले कभी अपना पहला संस्करण देखा है, इसलिए मेरे अनुभव से यह अधिक आम मुहावरे है।

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

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