सरणी डेटा में संशोधन को कैसे रोकें?


9

कहो कि मेरे पास एक वर्ग है जो इस तरह दिखता है (यह सिर्फ एक उदाहरण है):

class A {
    double *ptr;
public:
    A() : ptr( new double[100] ) {}
    A( const A &other ) {
        other.ptr[7] = 15;
    }
    void doNotChangeMyData() const {
        ptr[43] = 14;
    }
    void changeMyData() {
        ptr[43] = 14;
    }
    ~A() { delete[] ptr; }
};

constदोनों प्रतिलिपि निर्माता और में doNotChangeMyDataसमारोह कर ताकि ptrबदला नहीं जा सकता; हालाँकि, यह अभी भी मुझे इंगित की गई सरणी की सामग्री को संशोधित करने की अनुमति देता है ptr

क्या केवल उदाहरणों ptrमें बदलाव से "सरणी constसावधान रहने" (या कच्चे सूचक से दूर जाने) की सामग्री को रोकने का कोई तरीका है ?

मुझे पता है कि मैं कुछ ऐसा कर सकता था

void doNotChangeMyData() const {
    const double *const ptr = this->ptr;
    ptr[43] = 14; // then this would fail to compile
}

लेकिन मुझे नहीं करना होगा ...


1
आप एकstd::vector
idclev 463035818

std::vector::operator[]()सही मानों को संशोधित कर सकते हैं?
मार्विनसीस्कुल

@ पूर्व-परिचित_463035818 संपादित प्रश्न इसलिए विकल्प नहीं है;) यह अधिक सैद्धांतिक प्रश्न है, लेकिन हां, vectorकाम करेगा।
क्रिसमम

2
@marvinIsSacul यकीन है, लेकिन std::vector::operator[]() constएक constसंदर्भ देता है
idclev 463035818

@ChrisMM मुझे क्या उम्मीद थी, बस कमरे में हाथी का उल्लेख करना चाहता था :)
idclev 463035818

जवाबों:


7

संकेत प्रचार नहीं करते हैं constconstप्रकार की double*पैदावार में जोड़ने पर double* const, जिसके परिणामस्वरूप गैर- constलैवल्यूज़ हो जाते हैं जब वे डीरफ़र किए जाते हैं।

इसके बजाय, आप एक का उपयोग कर सकते हैं std::vector:

class A {
    std::vector<double> data(100);
public:
    // no explicit copy ctor or dtor
};

a std::array:

class A {
    std::array<double, 100> data{};
public:
    // no explicit copy ctor or dtor
};

या बिलिन सरणी (अनुशंसित नहीं):

class A {
    double data[100] {};
public:
    // no explicit copy ctor or dtor
};

तीनों विकल्पों में से सभी प्रचार करते हैं const

यदि आप वास्तव में पॉइंटर्स (दृढ़ता से अनुशंसित नहीं) का उपयोग करना चाहते हैं, तो कम से कम std::unique_ptrमैन्युअल मेमोरी प्रबंधन से बचने के लिए उपयोग करें । आप std::experimental::propagate_constलाइब्रेरी फंडामेंटल 2 TS से रैपर का उपयोग कर सकते हैं :

class A {
    std::experimental::propagate_const<std::unique_ptr<double[]>> ptr;
public:
    A()
        : ptr{new double[100] {}}
    {
    }
    // manual copy ctor
    A(const A& other)
        : ptr{new double[100]}
    {
        std::copy_n(other.ptr.get(), 100, ptr.get());
    }
    // defaulted move ctor & dtor
    // assignment operator, etc.
    // ...
};

यह अभी तक मानक में नहीं है, लेकिन कई संकलक इसका समर्थन करते हैं। बेशक, यह दृष्टिकोण उचित कंटेनरों से नीच है।


अंतर्निहित डेटा प्रकार को बदलने के बिना ऐसा करने की कोशिश करना, किसी भी चीज़ से अधिक सैद्धांतिक सवाल। यदि संभव नहीं है, तो मैं इसे संभव नहीं मानूंगा।
क्रिसमम 12

@ क्रिसमम मैंने एक पॉइंटर समाधान के साथ उत्तर को अपडेट किया है। पर क्यों :)
LF

"क्यों" जवाब देना मुश्किल है, अधिक जिज्ञासा। "निर्मित सरणी" या std::arrayयदि आप संकलन समय पर आकार नहीं जानते हैं, तो काम न करें। vectorओवरहेड जोड़ता है; unique_ptrओवरहेड नहीं जोड़ता है, लेकिन यदि पॉइंटर को साझा करने की आवश्यकता है, तो आपको ज़रूरत है shared_ptrजो ओवरहेड को जोड़ता है। मुझे नहीं लगता कि वीएस वर्तमान में समर्थन करता है propagate_const(कम से कम हेडर फ़ाइल जिसे cppreference द्वारा संदर्भित किया गया है, वह मौजूद नहीं है /std:c++latest) :(
क्रिसमम

1
@ChrisMM का ओवरहेड vectorअक्सर टीबीएच को कम करके आंका जाता है, खासकर मैनुअल मेमोरी मैनेजमेंट के प्रयास की तुलना में। इसके अलावा, यदि आप मैन्युअल रूप से पॉइंटर्स साझा करते हैं, तो आपको एक संदर्भ गणना का उपयोग करना होगा, इसलिए ओवरहेड अजीब नहीं है shared_ptr। मुझे नहीं पता था कि VS propagate_constअभी तक समर्थन नहीं करता है (GCC और Clang दोनों इसे IIRC का समर्थन करते हैं), लेकिन यह कल्पना के अनुसार हमारे अपने रोल आउट करने के लिए कठिन नहीं है।
LF

मैं मानता हूं कि ओवरहेड न्यूनतम है, लेकिन प्रदर्शन के महत्वपूर्ण (मेमोरी और समय) होने पर कच्चे पॉइंटर्स का उपयोग करने के कारण हैं। मैं कभी-कभी vectorइसकी सामग्री का उपयोग करता हूं .data()या इसके माध्यम से &vec[0]सीधे काम करता हूं । साझा किए जाने के मामले में, मेरे पास अक्सर सूचक का एक मालिक होता है जो बनाता है और हटाता है, लेकिन अन्य वर्ग डेटा साझा करते हैं।
क्रिसएमएम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.