C ++ 11 रेंज आधारित लूप: मूल्य के अनुसार आइटम प्राप्त करें या कॉन्स्टेंस के संदर्भ में


215

रेंज आधारित छोरों के कुछ उदाहरणों को पढ़ना वे दो मुख्य तरीके 1 , 2 , 3 , 4 का सुझाव देते हैं

std::vector<MyClass> vec;

for (auto &x : vec)
{
  // x is a reference to an item of vec
  // We can change vec's items by changing x 
}

या

for (auto x : vec)
{
  // Value of x is copied from an item of vec
  // We can not change vec's items by changing x
}

कुंआ।

जब हमें vecआइटम बदलने की आवश्यकता नहीं होती है , तो IMO, उदाहरण दूसरा संस्करण (मूल्य के अनुसार) का उपयोग करने का सुझाव देते हैं। वे कुछ सुझाव क्यों नहीं देते हैं जो constसंदर्भ (कम से कम मुझे कोई प्रत्यक्ष सुझाव नहीं मिला है):

for (auto const &x : vec) // <-- see const keyword
{
  // x is a reference to an const item of vec
  // We can not change vec's items by changing x 
}

क्या यह बेहतर नहीं है? क्या यह प्रत्येक पुनरावृत्ति में निरर्थक प्रतिलिपि से बचता नहीं है जबकि यह एक है const?

जवाबों:


390

यदि आप आइटम नहीं बदलना चाहते हैं और साथ ही प्रतियां बनाने से बचना चाहते हैं , तो auto const &सही विकल्प है:

for (auto const &x : vec)

जो भी आपको उपयोग करने का सुझाव देता है auto &वह गलत है। उन पर ध्यान न दें।

यहाँ पुनरावृत्ति है:

  • auto xजब आप प्रतियों के साथ काम करना चाहते हैं तब चुनें ।
  • चुनें auto &xकि आप मूल वस्तुओं के साथ कब काम करना चाहते हैं और उन्हें संशोधित कर सकते हैं।
  • चुनें auto const &xकि आप मूल वस्तुओं के साथ कब काम करना चाहते हैं और उन्हें संशोधित नहीं करेंगे।

21
महान जवाब के लिए धन्यवाद। मुझे लगता है कि यह भी बताया जाना चाहिए कि const auto &xआपकी तीसरी पसंद के बराबर है।
SMG

7
@mloskot: यह बराबर है। (और आपका क्या मतलब है "लेकिन यह एक ही वाक्य रचना है" ? वाक्यविन्यास अलग-अलग है।)
नवाज़

14
गुम: auto&&जब आप एक अनावश्यक प्रतिलिपि नहीं बनाना चाहते हैं, और परवाह नहीं है कि आप इसे संशोधित करते हैं या नहीं, और आप बस काम करना चाहते हैं।
यक्क - एडम नेवरुमोंट

4
क्या संदर्भ अंतर प्रतियों पर लागू होता है, यदि आप केवल मौलिक / डबल जैसे मूलभूत प्रकारों के साथ काम कर रहे हैं?

4
@racarate: मैं समग्र गति पर टिप्पणी नहीं कर सकता , और मुझे लगता है कि कोई भी, पहले इसे रूपरेखा के बिना नहीं कर सकता। सच कहूं, तो मैं अपनी पसंद के आधार पर कोड की स्पष्टता के आधार पर अभ्यस्त नहीं हूं। अगर मैं अपरिवर्तनीयता चाहता हूं, तो मैं इसका इस्तेमाल करूंगा const। हालांकि, यह होगा auto const &, या auto const थोड़ा अंतर है। मैं auto const &बस अधिक सुसंगत होना चाहता हूँ ।
नवाज

23

यदि आपके पास std::vector<int>या है std::vector<double>, तो इसके autoबजाय इसका उपयोग करना ठीक है (मूल्य कॉपी के साथ) const auto&, क्योंकि कॉपी करना intया खरीदना doubleसस्ता है:

for (auto x : vec)
    ....

लेकिन अगर आपके पास एक है std::vector<MyClass>, जहां MyClassकुछ गैर-तुच्छ कॉपी शब्दार्थ हैं (जैसे std::string, कुछ जटिल कस्टम वर्ग, आदि) तो मैं सुझाव देता हूं कि const auto&गहरी-प्रतियों से बचने के लिए उपयोग करें :

for (const auto & x : vec)
    ....

3

जब हमें vecआइटम बदलने की आवश्यकता नहीं होती है , तो उदाहरण पहले संस्करण का उपयोग करने का सुझाव देते हैं।

फिर वे एक गलत सुझाव देते हैं।

वे कुछ सुझाव क्यों नहीं देते हैं, जो संदर्भ को संदर्भित करता है

क्योंकि वे एक गलत सुझाव देते हैं :-) जो आप उल्लेख करते हैं वह सही है। यदि आप केवल एक वस्तु का निरीक्षण करना चाहते हैं , तो एक प्रति बनाने की आवश्यकता नहीं है, और इसके लिए एक गैर- constसंदर्भ होने की आवश्यकता नहीं है।

संपादित करें:

मैं उन संदर्भों को देखता हूं जिन्हें आप लिंक करते हैं, सभी intमानों की श्रेणी या कुछ अन्य मौलिक डेटा प्रकार पर पुनरावृति के उदाहरण प्रदान करते हैं । उस मामले में, चूंकि कॉपी करना intमहंगा नहीं है, इसलिए एक कॉपी बनाना मूल रूप से एक अवलोकन के बराबर (यदि अधिक कुशल नहीं है) के बराबर है const &

हालांकि, यह उपयोगकर्ता-परिभाषित प्रकारों के लिए सामान्य रूप से मामला नहीं है। UDTs कॉपी करना महंगा हो सकता है, और यदि आपके पास कॉपी बनाने का कोई कारण नहीं है (जैसे कि मूल वस्तु में फेरबदल किए बिना प्राप्त वस्तु को संशोधित करना), तो इसका उपयोग करना बेहतर होगा const &


1

मैं यहाँ इसके विपरीत जा रहा हूँ और कहता हूँ कि auto const &लूप के लिए किसी रेंज की आवश्यकता नहीं है । मुझे बताएं कि क्या आपको लगता है कि निम्नलिखित कार्य मूर्खतापूर्ण है (इसके उद्देश्य में नहीं है, लेकिन जिस तरह से यह लिखा गया है):

long long SafePop(std::vector<uint32_t>& v)
{
    auto const& cv = v;
    long long n = -1;
    if (!cv.empty())
    {
        n = cv.back();
        v.pop_back();
    }
    return n;
}

यहाँ, लेखक ने vउन सभी परिचालनों के लिए उपयोग करने के लिए एक कास्ट रेफ़रेंस बनाया है जो v को संशोधित नहीं करते हैं। यह मूर्खतापूर्ण है, मेरी राय में, और एक ही तर्क को auto const &लूप के लिए आधारित रेंज में वेरिएबल के रूप में उपयोग करने के लिए बनाया जा सकता है। auto &


3
@BenjaminLindley: इसलिए मैं यह अनुमान लगा सकता हूं कि आप const_iteratorलूप के लिए भी बहस करेंगे ? जब आप इस पर पुनरावृति करते हैं, तो आप यह कैसे सुनिश्चित करते हैं कि आप कंटेनर से मूल आइटम नहीं बदलते हैं?
नवाज

2
@BenjaminLindley: आपका कोड बिना संकलन क्यों नहीं होगा const_iterator? मुझे लगता है, कंटेनर जो आप पर itter है, है const। लेकिन इसके constसाथ शुरुआत क्यों करनी है? कहीं आप constयह सुनिश्चित करने के लिए उपयोग कर रहे हैं कि क्या?
नवाज

8
वस्तुओं constको बनाने का लाभ कक्षाओं में उपयोग करने के फायदे private/ जैसा है protected। यह आगे की गलतियों से बचा जाता है।
मसूद

2
@BenjaminLindley: ओह, मैंने इसे अनदेखा कर दिया। फिर इस मामले में, कार्यान्वयन मूर्खतापूर्ण है। लेकिन अगर वह फ़ंक्शन संशोधित नहीं हुआ v, तो कार्यान्वयन ठीक IMO होगा। और यदि लूप कभी भी उन वस्तुओं को संशोधित नहीं करता है, जिनके माध्यम से यह पुनरावृत्ति करता है, तो मेरे लिए रेफरी होना सही लगता है const। मैं हालांकि आपकी बात देखता हूं। खदान यह है कि लूप एक कोड इकाई का प्रतिनिधित्व करता है, जैसे फ़ंक्शन करता है, और उस इकाई के भीतर कोई निर्देश नहीं है, जो मूल्य को संशोधित करने की आवश्यकता है। इसलिए, आप पूरी यूनिट को "टैग" कर सकते हैं const, जैसा कि आप constसदस्य फ़ंक्शन के साथ करेंगे ।
एंडी प्रोल

1
तो आप सोचते हैं कि const &रेंज-आधारित मूर्खतापूर्ण है, क्योंकि आपने एक काल्पनिक प्रोग्रामर का एक अप्रासंगिक काल्पनिक उदाहरण लिखा है जिसने cv -qualification के साथ मूर्खतापूर्ण कुछ किया था ? ... ठीक है
अंडरस्कोर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.