2012-04-22 14 views
6

एक वर्ग एक std::vector<int*> शामिल हैं। बाहरी कोड को इस वेक्टर तक केवल पढ़ने के लिए उपयोग की आवश्यकता है, सामग्री को संशोधित करने में सक्षम नहीं होना चाहिए (न तो पॉइंटर्स या उनकी सामग्री)। कक्षा के अंदर, मूल्यों मई परिवर्तन (जैसे double_values(), और इसलिए उन्हें भंडारण के रूप में एक std::vector<const int*> संभव नहीं है।उपचार वेक्टर <int*> कॉपी किए बिना (C++ 0x)

वहाँ एक प्रतिलिपि बनाने के बिना एक std::vector<const int*> रूप std::vector<int*> वापस जाने के लिए कोई तरीका है? यह की तरह लगता है वहाँ होना चाहिए हो सकता है, क्योंकि स्थिरांक बस संकलन समय पर काम कर रहा है कहने के लिए क्या और बदला नहीं जा सकता कर सकते हैं

कोड:। (g++ -std=c++0x साथ संकलन)

class ReadOnlyAccess 
{ 
public: 
    ReadOnlyAccess(const std::vector<int*> & int_ptrs_param): 
    int_ptrs(int_ptrs_param) 
    { 
    } 
    const std::vector<int*> & get_int_ptrs() const 
    { 
    return int_ptrs; 
    } 
    std::vector<const int*> safely_get_int_ptrs() const 
    { 
    // will not compile (too bad): 
    // return int_ptrs; 

    // need to copy entire vector 
    std::vector<const int*> result(int_ptrs.size()); 
    for (int k=0; k<int_ptrs.size(); k++) 
     result[k] = int_ptrs[k]; 
    return result; 
    } 
    void double_values() 
    { 
    for (int*p : int_ptrs) 
     *p *= 2; 
    } 
    void print() const 
    { 
    for (const int * p : int_ptrs) 
     std::cout << *p << " "; 
    std::cout << std::endl; 
    } 
private: 
    std::vector<int*> int_ptrs; 
}; 

int main() { 
    ReadOnlyAccess roa(std::vector<int*>{new int(10), new int(20), new int(100)}); 
    std::vector<const int*> safe_int_ptrs = roa.safely_get_int_ptrs(); 
    // does not compile (good) 
    // *safe_int_ptrs[0] = -100000; 
    roa.print(); 

    const std::vector<int*> & int_ptrs = roa.get_int_ptrs(); 
    // changes are made to the internal class values via the accessor! nooooo! 
    *int_ptrs[0] = -100000; 
    roa.print(); 

    return 0; 
} 
+0

[वेक्टर और कॉन्स] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/2102244/vector-and-const) –

+0

देखें http://stackoverflow.com/questions/2868485/cast-vectort-to- vectorconst-t – WeaselFox

+2

@ बो: वह प्रश्न वास्तव में इसका उत्तर नहीं देता है। और WeaselFox 'सूचक संकेत के कारण भी अप्रासंगिक है। – Xeo

उत्तर

4

retu यदि आप कॉन्स्ट पॉइंटर्स को वैसे भी रखना चाहते हैं तो वेक्टर को घुमाने पर एक प्रतिलिपि होगी।

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

#include <vector> 
#include <iostream> 

class Data 
{ 
public: 

    //...whatever needed to fill the values 

    // here we assume that Func is equivalent to std::function< void (int)> or std::function< void (const int&) > and can return anything that will be ignored here. 
    template< class Func > 
    void for_each_value(Func func) const // read-only 
    { 
     for(const int* value : m_values) // implicit conversion 
     { 
      func(*value); // read-only reference (const &), or copy 
      // if func needs to work with the adress of the object, it still can by getting a reference to it and using & to get it's adress 
     } 
    } 


    void print() const 
    { 
     std::cout << "\nData values: \n"; 
     for_each_value([](const int value) { std::cout << " "<< value << '\n'; }); 
    } 

    void count_values() const { return m_values.size(); } 

private: 

    std::vector<int*> m_values; 

}; 



int main() 
{ 
    Data data; 
    // ... whatever needed to fill the data 

    data.print();  

    std::vector<int> modified_values; 
    data.for_each_value([&](int value) { modified_values.push_back(value + 42); }); 

    return 0; 
} 

अगर आप समझते हैं कि, और मूल्यों का उपयोग करने के अलग अलग तरीकों में कुछ आधा सामान्य एल्गोरिदम को कम किया जा सकता है, तो यह आपके कोड को आसान बनाने के लिए और आप को उजागर करने के बजाय अपने संरचनाओं के अंदर डेटा रखने के लिए अनुमति देगा यह हिम्मत है।

+0

आप 'std :: for_each' के बारे में जानते हैं, है ना? – jalf

+0

जाहिर है। तुम क्यों पूछते हो, बिल्कुल? यहां कक्षा के बाहर इस्तेमाल किया गया std :: for_each मदद नहीं करेगा क्योंकि इसे वास्तविक कंटेनर इटरेटर का खुलासा करने की आवश्यकता होगी, या एक प्रतिलिपि बनाना होगा, जिसे प्रश्न से बचा जाना चाहिए। मैं बिना किसी लाभ के, std :: for_each द्वारा for_each_value में लूप को प्रतिस्थापित कर सकता था। मेरे उत्तर का मुद्दा यह है कि कंटेनर की कोई प्रति नहीं है, और जो कुछ भी ट्रैवर्सल के लिए एल्गोरिदम है, आपको कक्षा की सामग्री का खुलासा करने की आवश्यकता नहीं है यदि आप जानते हैं कि कक्षा के उपयोगकर्ताओं द्वारा किस तरह की ट्रैवर्सल की आवश्यकता है। जाहिर है, अगर आप नहीं जानते हैं, तो यज्ञ को गले लगाओ। – Klaim

+0

कहा जा रहा है कि, कुछ मामलों की आवश्यकता है कि कक्षा Iterators द्वारा सामग्री का पर्दाफाश करें। लेकिन मुझे नहीं लगता कि यह विशिष्ट प्रश्न के लिए जरूरी है। – Klaim

1

आप कस्टम iterators के माध्यम से स्थिरांक मान के लिए एक दृश्य प्रदान कर सकते हैं। हम (लेकिन सीधे उदा x[0] = -1 में) की तरह .base() के माध्यम से उठाई मानों को संशोधित कर सकता है

#include <boost/iterator/indirect_iterator.hpp> 

class ReadOnlyAccess 
{ 
// ... 
    typedef boost::indirect_iterator<const int* const*, const int> const_val_iter_type; 
    const_val_iter_type cval_begin() { 
     return it_t{const_cast<const int* const*>(&int_ptrs[0])}; 
    } 
} 

int main() { 
    // ... 
    auto x = roa.cval_begin(); 
    std::cout << x[0] <<' ' << x[1] << x[2] <<'\n'; 
    // we can still access the pointers themselves via .base() member function: 
    for (int i=0; i<3; ++i) 
     assert(x.base()[i] == safe_int_ptrs[i]); 
    // the values are read-only, the following does not compile: 
    // x[0] = -1; 
    // **x.base() = -1; 
    // *x.base() = nullptr; 
} 

अगर हम const_val_iter_type के लिए boost::indirect_iterator<typename std::vector<int*>::const_iterator, const int> इस्तेमाल किया, है, तो यह समाधान सामान्य नहीं है: एक आसान तरीका है boost::iterator उपयोग करने के लिए किया जाएगा।

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