जवाबों:
यह काफी सरल है। कहो मेरे पास एक वेक्टर है:
std::vector<int> vec;
मैं इसे कुछ आंकड़ों से भरता हूं। फिर मैं इसके लिए कुछ पुनरावृत्तियों को प्राप्त करना चाहता हूं। शायद उनके आसपास से गुजर जाए। हो सकता है std::for_each
:
std::for_each(vec.begin(), vec.end(), SomeFunctor());
C ++ 03 में, यह प्राप्त पैरामीटर SomeFunctor
को संशोधित करने में सक्षम होने के लिए स्वतंत्र था । ज़रूर, SomeFunctor
इसके पैरामीटर को मान या द्वारा ले सकता है const&
, लेकिन यह सुनिश्चित करने का कोई तरीका नहीं है कि यह करता है। इस तरह मूर्खतापूर्ण कुछ किए बिना नहीं:
const std::vector<int> &vec_ref = vec;
std::for_each(vec_ref.begin(), vec_ref.end(), SomeFunctor());
अब, हम परिचय देते हैं cbegin/cend
:
std::for_each(vec.cbegin(), vec.cend(), SomeFunctor());
अब, हमारे पास सिंटैक्टिक आश्वासन हैं जो SomeFunctor
वेक्टर के तत्वों (एक कास्ट-कास्ट के बिना, बिल्कुल) को संशोधित नहीं कर सकते हैं। हम स्पष्ट रूप से प्राप्त करते हैं const_iterator
, और इसलिए SomeFunctor::operator()
इसके साथ बुलाया जाएगा const int &
। यदि यह इसे पैरामीटर के रूप में लेता है int &
, तो C ++ कंपाइलर त्रुटि जारी करेगा।
C ++ 17 में इस समस्या का एक और अधिक सुंदर समाधान है std::as_const
:। रेंज-आधारित का उपयोग करते समय, कम से कम यह सुरुचिपूर्ण है for
:
for(auto &item : std::as_const(vec))
यह बस const&
प्रदान की गई वस्तु के लिए एक रिटर्न देता है ।
std::cbegin/cend
जिस तरह से std::begin/std::end
मौजूद हैं, कोई मुफ्त कार्य नहीं हैं। यह समिति द्वारा एक निरीक्षण था। यदि वे कार्य मौजूद थे, तो आमतौर पर उनका उपयोग करने का तरीका होगा।
std::cbegin/cend
C ++ 14 में जोड़ा जाएगा। देखें en.cppreference.com/w/cpp/iterator/begin
for(auto &item : std::as_const(vec))
बराबर है for(const auto &item : vec)
?
const
संदर्भ पर रखकर संशोधित नहीं किया जाएगा । निकोल के कंटेनर को कास्ट के रूप में देखा गया है, इसलिए auto
एक const
संदर्भ को घटाता है । IMO auto const& item
आसान और स्पष्ट है। यह स्पष्ट नहीं है कि std::as_const()
यहाँ अच्छा क्यों है; मैं देख सकता हूँ कि यह उपयोगी होगा जब कुछ गैर- const
जेनेरिक कोड पास करने के लिए जहां हम उस प्रकार को नियंत्रित नहीं कर सकते हैं जो इस्तेमाल किया जाता है, लेकिन रेंज- के साथ for
, हम कर सकते हैं, इसलिए ऐसा लगता है जैसे मेरे लिए वहां जोड़ा गया शोर है।
निकोल बोलस ने अपने उत्तर में जो कहा, उससे परे नए auto
कीवर्ड पर विचार करें :
auto iterator = container.begin();
इसके साथ auto
, यह सुनिश्चित करने का कोई तरीका नहीं है कि begin()
एक निरंतर ऑपरेटर को एक गैर-स्थिर कंटेनर संदर्भ के लिए लौटाया जाए। तो अब आप करते हैं:
auto const_iterator = container.cbegin();
const_iterator
बस एक और पहचानकर्ता है। न तो संस्करण सामान्य सदस्य टाइपडिफ्स की खोज का उपयोग करता है decltype(container)::iterator
या decltype(container)::const_iterator
।
const_iterator
साथ प्राप्त करें: ऑब्जेक्ट तर्क को अर्हता प्राप्त करने के लिए auto
कहा जाता है एक सहायक फ़ंक्शन टेम्पलेट लिखें make_const
।
इसे एक व्यावहारिक usecase के रूप में लें
void SomeClass::f(const vector<int>& a) {
auto it = someNonConstMemberVector.begin();
...
it = a.begin();
...
}
असाइनमेंट विफल हो जाता है क्योंकि it
एक नॉनस्टॉक इटेटर है। यदि आप शुरू में केगिन का उपयोग करते थे, तो इट्रेटर का सही प्रकार होता।
से http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1674.pdf :
ताकि एक प्रोग्रामर सीधे नॉन-कॉस्ट कंटेनर से भी एक const_iterator प्राप्त कर सके
उन्होंने इसका उदाहरण दिया
vector<MyType> v;
// fill v ...
typedef vector<MyType>::iterator iter;
for( iter it = v.begin(); it != v.end(); ++it ) {
// use *it ...
}
हालांकि, जब एक कंटेनर ट्रावर्सल केवल निरीक्षण के लिए अभिप्रेत है, तो संकलक का उपयोग करने के लिए एक आम तौर पर पसंदीदा अभ्यास है, ताकि कंपाइलर को कांस्ट-शुद्धता उल्लंघन का निदान करने की अनुमति मिल सके
नोट वर्किंग पेपर भी एडाप्टर टेम्पलेट्स का उल्लेख है, कि अब के रूप में अंतिम रूप दे दिया गया है कि std::begin()
और std::end()
और वह भी देशी सरणियों के साथ काम करते हैं। संबंधित std::cbegin()
और std::cend()
इस समय के रूप में गायब हैं, लेकिन उन्हें भी जोड़ा जा सकता है।
बस इस सवाल पर लड़खड़ा गया ... मुझे पता है कि यह बहुत बुरा जवाब है और यह सिर्फ एक पक्ष नोड है ...
auto const it = container.begin()
फिर एक अलग प्रकार है auto it = container.cbegin()
के लिए अंतर int[5]
(पॉइंटर का उपयोग करके, जो मुझे पता है कि शुरुआत विधि नहीं है, लेकिन अच्छी तरह से अंतर दिखाएं ... लेकिन सी + + 14 के लिए काम करेंगे std::cbegin()
और std::cend()
, जो अनिवार्य रूप से एक का उपयोग करना चाहिए जब वह यहां है ...)
int numbers = array[7];
const auto it = begin(numbers); // type is int* const -> pointer is const
auto it = cbegin(numbers); // type is int const* -> value is const
iterator
और const_iterator
इनहेरिटेंस संबंध और एक अंतर्निहित रूपांतरण तब होता है जब अन्य प्रकार के साथ तुलना या असाइन किया जाता है।
class T {} MyT1, MyT2, MyT3;
std::vector<T> MyVector = {MyT1, MyT2, MyT3};
for (std::vector<T>::const_iterator it=MyVector.begin(); it!=MyVector.end(); ++it)
{
// ...
}
उपयोग करने cbegin()
और cend()
इस मामले में प्रदर्शन में वृद्धि होगी।
for (std::vector<T>::const_iterator it=MyVector.cbegin(); it!=MyVector.cend(); ++it)
{
// ...
}
const
मुख्य लाभ प्रदर्शन है (जो यह नहीं है: यह शब्दार्थ रूप से सही और सुरक्षित कोड है)। लेकिन, जब आपके पास एक बिंदु होता है, (ए) auto
एक गैर-मुद्दा बनाता है; (बी) प्रदर्शन के बारे में बात करने में, आपको एक मुख्य बात याद आती है जो आपको यहाँ करनी चाहिए थी: लूप end
के इनिट-कंडीशन में इसकी एक कॉपी घोषित करके इटरेटर को कैश करें for
, और एक नई कॉपी प्राप्त करने के बजाय उसकी तुलना करें हर पुनरावृत्ति के लिए मूल्य। इससे आपकी बात बेहतर होगी। : P
const
निश्चित रूप से बेहतर प्रदर्शन को प्राप्त करने में मदद कर सकता है, न कि const
कीवर्ड में कुछ जादू के कारण, बल्कि इसलिए कि कंपाइलर कुछ अनुकूलन कर सकता है यदि यह जानता है कि डेटा संशोधित नहीं किया जाएगा, जो अन्यथा संभव नहीं होगा। चेक इस बिट इस का लाइव उदाहरण के लिए एक जैसन टर्नर की बात से।
const
प्रदर्शन लाभ के लिए नेतृत्व कर सकते हैं (लगभग अप्रत्यक्ष रूप से); यदि कोई व्यक्ति इसे पढ़ता है तो मुझे लगता है कि "मैं यह जोड़ने की जहमत नहीं उठाऊंगा const
कि उत्पन्न कोड किसी भी तरह से प्रभावित नहीं होता है", जो कि सच नहीं है।
इसकी सरल, cbegin एक निरंतर पुनरावृत्ति देता है जहाँ से एक पुनरावृत्तिक शुरू होता है
बेहतर समझ के लिए दो परिदृश्यों को यहाँ ले जाने दें
दृष्टांत 1 :
#include <iostream>
using namespace std;
#include <vector>
int main(int argc, char const *argv[])
{
std::vector<int> v;
for (int i = 1; i < 6; ++i)
{
/* code */
v.push_back(i);
}
for(auto i = v.begin();i< v.end();i++){
*i = *i + 5;
}
for (auto i = v.begin();i < v.end();i++){
cout<<*i<<" ";
}
return 0;
}
यह चलेगा क्योंकि यहाँ पुनरावृत्ति i स्थिर नहीं है और इसे 5 से बढ़ाया जा सकता है
अब चलो cbegin का उपयोग करें और उन्हें लगातार चलने वाले परिदृश्य के रूप में दर्शाते हुए देखें - 2:
#include <iostream>
using namespace std;
#include <vector>
int main(int argc, char const *argv[])
{
std::vector<int> v;
for (int i = 1; i < 6; ++i)
{
/* code */
v.push_back(i);
}
for(auto i = v.cbegin();i< v.cend();i++){
*i = *i + 5;
}
for (auto i = v.begin();i < v.end();i++){
cout<<*i<<" ";
}
return 0;
}
यह काम नहीं करने वाला है, क्योंकि आप कैबिन और सेंड का उपयोग करके मूल्य को अपडेट नहीं कर सकते हैं जो निरंतर पुनरावृत्त रिटर्न देता है