क्या const_cast सुरक्षित है?


92

मुझे बहुत जानकारी नहीं मिल रही है const_cast। एकमात्र जानकारी जो मुझे मिल सकती है (स्टैक ओवरफ्लो पर) है:

const_cast<>()जोड़ने के लिए / एक चर के निकाले जाने स्थिरांक (सत्ता) (या अस्थिर सत्ता) किया जाता है।

इससे मुझे घबराहट होती है। एक const_castअप्रत्याशित व्यवहार का उपयोग कर सकता है? यदि ऐसा है तो क्या?

वैकल्पिक रूप से, कब उपयोग करना ठीक है const_cast?


4
शीर्ष उत्तर कुछ ऐसा है जो स्पष्ट रूप से स्पष्ट हो सकता है, लेकिन यह बताने योग्य है कि यदि आप किसी मूल constवस्तु को de const-ed संदर्भ / पॉइंटर के माध्यम से संशोधित करने का प्रयास करते हैं, तो यह असुरक्षित हो जाता है । यदि, इसके बजाय, आप केवल const_castखराब तरीके से (या, मेरे मामले में, आलसी होकर) API को काम करने के लिए निगलना चाहते हैं, जो केवल एक गैर- constसंदर्भ को स्वीकार करता है, लेकिन केवल constविधियों में उपयोग किया जाएगा ... कोई बात नहीं।
अंडरस्कोर_ डी

1
@underscore_d: इस सवाल का एक और सटीक संस्करण (और उत्तर) जो इसे
पीटर कॉर्ड्स

जवाबों:


88

const_castकेवल तभी सुरक्षित है जब आप एक वैरिएबल कास्ट कर रहे हैं जो मूल रूप से गैर- था const। उदाहरण के लिए, यदि आपके पास एक फ़ंक्शन है जो एक पैरामीटर लेता है const char *, और आप एक परिवर्तनीय में पास करते हैं char *, तो यह const_castउस पैरामीटर के लिए सुरक्षित है जो इसे वापस करता है char *और इसे संशोधित करता है। हालांकि, यदि मूल चर वास्तव में था const, तो उपयोग करने const_castसे अपरिभाषित व्यवहार होगा।

void func(const char *param, size_t sz, bool modify)
{
    if(modify)
        strncpy(const_cast<char *>(param), sz, "new string");
    printf("param: %s\n", param);
}

...

char buffer[16];
const char *unmodifiable = "string constant";
func(buffer, sizeof(buffer), true);  // OK
func(unmodifiable, strlen(unmodifiable), false); // OK
func(unmodifiable, strlen(unmodifiable), true);  // UNDEFINED BEHAVIOR

9
यह सच नहीं है। सी ++ मानक। §7.1.​5.1/4 says Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior कोई भी प्रयास ! मूल चर के बारे में कोई शब्द नहीं हैं।
एलेक्सी मैलिस्तोव

20
@Alexey: मूल चर उस चीज़ के बारे में है जिसे इंगित या संदर्भित किया जाता है। आप एक नॉन-कॉस्ट ऑब्जेक्ट के लिए एक कॉन्स्टेक्ट रेफरेंस ले सकते हैं, और इसलिए, इसे एक रेफरटेबल रेफरेंस के लिए कास्टिंग करना अच्छी तरह से परिभाषित व्यवहार है क्योंकि संदर्भित ऑब्जेक्ट वास्तव में कॉन्स्टेबल नहीं है।
पिल्ला

43
@Alexey Malistov: नहीं। एक "ऑब्जेक्ट" मेमोरी में कब्जे वाले वास्तविक क्षेत्र को संदर्भित करता है ()1.7)। एक नॉन-कॉस्ट ऑब्जेक्ट के लिए एक कॉस्ट रेफरेंस लेने से ऑब्जेक्ट कॉस्ट नहीं बनता है। केवल एक स्थिरांक के मामले में संदर्भ पैरामीटर ( नहीं एक स्थिरांक सूचक पैरामीटर) संकलक चुपचाप एक प्रति (§5.2.2 / 5) बनाने की अनुमति दी है, यहां ऐसा मामला नहीं है।
एडम रोसेनफील्ड

8
"हालांकि, यदि मूल चर वास्तव में कांस्टेबल था, तो const_cast का उपयोग करने से अपरिभाषित व्यवहार होगा" यह कथन गलत है।
को ऑर्बिट में

7
यह नहीं यूबी उपयोग करने के लिए const_castदूर करने के लिए constकुछ है कि शुरू में घोषित किया गया था से const। लेकिन यह है यूबी वास्तव में उस वस्तु को लिखने की कोशिश करने के लिए। जब तक आप पढ़ते हैं तब तक आप ठीक हैं और अपने आप const_castमें यूबी का कारण नहीं है। यह एक भयानक विचार है, लेकिन यह स्वाभाविक रूप से यूबी नहीं है।
जेस्पर जुहल

35

मैं उन दो स्थितियों के बारे में सोच सकता हूं, जहां const_cast सुरक्षित और उपयोगी है (अन्य वैध मामले हो सकते हैं)।

एक तब होता है जब आपके पास एक कॉन्स्टेंट इंस्टेंस, रेफरेंस या पॉइंटर होता है, और आप एक पॉइंटर के लिए एक पॉइंटर या रेफरेंस पास करना चाहते हैं जो कॉन्स्टीट्यूशन सही न हो, लेकिन यह कि आप CERTAIN ऑब्जेक्ट को संशोधित नहीं करेंगे। आप पॉइंटर को संकुचित कर सकते हैं और इसे एपीआई में पास कर सकते हैं, यह विश्वास करते हुए कि यह वास्तव में कुछ भी नहीं बदलेगा। उदाहरण के लिए:

void log(char* text);   // Won't change text -- just const-incorrect

void my_func(const std::string& message)
{
    log(const_cast<char*>(&message.c_str()));
}

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

class MyClass
{
    char cached_data[10000]; // should be mutable
    bool cache_dirty;        // should also be mutable

  public:

    char getData(int index) const
    {
        if (cache_dirty)
        {
          MyClass* thisptr = const_cast<MyClass*>(this);
          update_cache(thisptr->cached_data);
        }
        return cached_data[index];
    }
};

यह ... इस प्रश्न का उत्तर नहीं देता है। उन्होंने पूछा कि const_castक्या अपरिभाषित व्यवहार का कारण बन सकता है, न कि इसके उपयोगी अनुप्रयोग क्या हैं
माइकल मिरोज़ेक

13
सवाल से: "वैकल्पिक रूप से, कब कॉन्स्टोकैस्ट का उपयोग करना ठीक है?"
फ्रेड लार्सन

के रूप में "जब यह अपरिभाषित नहीं है"; वह उपयोगी होने पर इसके उदाहरणों की तलाश में नहीं है
माइकल Mrozek

हम केवल प्रश्न के अक्षरों पर चिपक सकते हैं। इसके आधार पर, एक चित्रण का उपयोग const_castएक मान्य उत्तर है। heसवालों में कोई दम नहीं है क्योंकि सवाल अकेला विषय है।
truthadjustr

24

मुझे यह विश्वास करना मुश्किल है कि यह एकमात्र जानकारी है जो आपको const_cast के बारे में मिल सकती है। दूसरे Google हिट से उद्धरण :

यदि आप एक ऐसी वस्तु की कमी को दूर करते हैं जिसे स्पष्ट रूप से कास्ट घोषित किया गया है, और इसे संशोधित करने का प्रयास किया गया है, तो परिणाम अपरिभाषित हैं।

हालांकि, यदि आप किसी ऐसी वस्तु की कमी को दूर करते हैं जिसे स्पष्ट रूप से कास्ट घोषित नहीं किया गया है, तो आप इसे सुरक्षित रूप से संशोधित कर सकते हैं।


ग्र्रेटरीट उत्तर, इस उत्तर के साथ संयोजित करें और आपको पूरी तस्वीर मिलती है।
बोबोबो

हम्म। आपके उत्तर में दूसरे कथन के बारे में, क्या मैं आपसे पूछ सकता हूं कि किसी वस्तु के लिए "कॉन्स्ट" नेस कैसे है जो स्पष्ट रूप से पहली जगह में कॉन्स्टेबल के रूप में घोषित नहीं किया गया था।
hAcKnRoCk

नॉन-कॉस्ट ऑब्जेक्ट को const, @Iam बनाने के बहुत सारे तरीके हैं। उदाहरण के लिए, ऑब्जेक्ट को एक कॉन्स्ट-रेफरेंस पैरामीटर के रूप में पास करें। या इसे पॉइंटर-टू-कॉन्स्ट को असाइन करें। या उपयोग करें const_cast। या उस पर एक कास्ट विधि कहते हैं।
रोब कैनेडी

12

आदम क्या कहता है। एक और उदाहरण जहां const_cast सहायक हो सकता है:

struct sample {
    T& getT() { 
        return const_cast<T&>(static_cast<const sample*>(this)->getT()); 
    }

    const T& getT() const { 
       /* possibly much code here */
       return t; 
    }

    T t;
};

हम पहले टाइप thisपॉइंट्स में कॉन्स्ट को जोड़ते हैं , फिर हम कॉन्स्टेबल वर्जन को कॉल करते हैं getT, और फिर हम कॉस्ट को रिटर्न टाइप से हटा देते हैं, जो कि वैध है क्योंकि tनॉन-कॉन्स्टेबल होना चाहिए (अन्यथा, नॉन-कॉस्ट वर्जन का कोई getTभी हिस्सा नहीं हो सकता है) कहा जाता है)। यह बहुत उपयोगी हो सकता है यदि आपको एक बड़ी फ़ंक्शन बॉडी मिली और आप अनावश्यक कोड से बचना चाहते हैं।


3
मैं स्थिरांक कास्ट को जोड़ने के लिए स्थिर का उपयोग करूंगा: static_cast <const sample *> (यह)। जब मैं const_cast पढ़ रहा हूं तो इसका मतलब है कि कोड संभावित रूप से कुछ खतरनाक कर रहा है, इसलिए मैं जब संभव हो इसका उपयोग करने से बचने की कोशिश करता हूं।
mfazekas

1
सही, पहला static_cast हो सकता है, या यहाँ तक कि implicit_cast (बूस्ट का) भी हो सकता है। मैं इसे स्थिर कलाकारों का उपयोग करके ठीक करूँगा। धन्यवाद
जोहान्स शाउब -

3
मैं आगे पीछे जाता हूं कि क्या बेहतर है const_castया नहीं static_castconst_castकेवल वही कर सकते हैं जो आप चाहते हैं: cv-qualifiers बदलें। static_cast'चुपचाप' अन्य कार्यों को कर सकते हैं जो आप इरादा नहीं करते हैं। हालांकि, पहली कास्ट पूरी तरह से सुरक्षित है, और static_castअधिक सुरक्षित है const_cast। मुझे लगता है कि यह एक ऐसी स्थिति है, जहां const_castआपके इरादे को बेहतर ढंग से static_castसंप्रेषित करता है , लेकिन आपके कार्यों की सुरक्षा को बेहतर बनाता है।
डेविड स्टोन

10

संक्षिप्त उत्तर नहीं है, यह सुरक्षित नहीं है।

लंबे उत्तर यह है कि यदि आप इसका उपयोग करने के लिए पर्याप्त जानते हैं, तो यह सुरक्षित होना चाहिए।

जब आप कास्टिंग कर रहे हैं, तो आप अनिवार्य रूप से क्या कह रहे हैं, "मुझे पता है कि कुछ कंपाइलर नहीं जानता है।" Const_cast के मामले में, आप जो कह रहे हैं वह यह है, "भले ही यह विधि एक नॉन-कॉस्ट संदर्भ या पॉइंटर में ले जाती है, मुझे पता है कि यह उस पैरामीटर को नहीं बदलेगा जो मैं इसे पास करता हूं।"

इसलिए यदि आप वास्तव में जानते हैं कि आप कलाकारों का उपयोग करने में क्या जानने का दावा कर रहे हैं, तो इसका उपयोग करना ठीक है।


5

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


1
क्या? यदि आपके पास अपरिवर्तनीय (कॉस्ट) ऑब्जेक्ट हैं, तो आप उन्हें थ्रेड के बीच तुच्छ रूप से साझा कर सकते हैं । तत्काल जो आपके कोड का एक टुकड़ा कॉन्स्टेंस-नेस को दूर कर देता है, आप अपने सभी थ्रेड सुरक्षा खो देते हैं! मैं इसके लिए डाउन-मोडेड क्यों हूं? sigh
मैट क्रुशांक

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

मुझे लगता है कि यह एक अच्छा जवाब है क्योंकि मैंने शब्द के आपके उपयोग में विश्वास और सुरक्षा के संकलक आशावादी भावनाओं के बारे में नहीं सोचा था constconstभरोसा है। const_castउस भरोसे को तोड़ रहा है :(
bobobobo

1
परस्पर और थ्रेड-सुरक्षा के बारे में: channel9.msdn.com/posts/…
MFH

-3
#include <iostream>
using namespace std;

void f(int* p) {
  cout << *p << endl;
}

int main(void) {
  const int a = 10;
  const int* b = &a;

  // Function f() expects int*, not const int*
  //   f(b);
  int* c = const_cast<int*>(b);
  f(c);

  // Lvalue is const
  //  *b = 20;

  // Undefined behavior
  //  *c = 30;

  int a1 = 40;
  const int* b1 = &a1;
  int* c1 = const_cast<int*>(b1);

  // Integer a1, the object referred to by c1, has
  // not been declared const
  *c1 = 50;

  return 0;
}

स्रोत: http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Frefword2conword_const_cast.htm


स्पैम लिंक के कारण डाउनवोटिंग
ट्रूटाडिजॉस्टर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.