छोरों के लिए रेंज-आधारित में अग्रेषण संदर्भों का उपयोग करने का क्या फायदा है?


115

const auto&यदि मैं केवल-पढ़ने के लिए ऑपरेशन करना चाहता हूँ तो पर्याप्त होगा। हालाँकि, मैं टकरा गया हूँ

for (auto&& e : v)  // v is non-const

हाल ही में एक दो बार। इससे मुझे आश्चर्य होता है:

क्या यह संभव है कि कुछ अस्पष्ट कोने के मामलों में auto&या की तुलना में अग्रेषण संदर्भों का उपयोग करने में कुछ प्रदर्शन लाभ है const auto&?

( shared_ptrअस्पष्ट कोने के मामलों के लिए एक संदिग्ध है)


मेरे पसंदीदा में मिले दो उदाहरणों को अपडेट करें :

मूल प्रकार से अधिक पुनरावृति होने पर कॉन्स्ट रेफरेंस का उपयोग करने का कोई नुकसान?
क्या मैं लूप के लिए रेंज-आधारित का उपयोग करके मानचित्र के मूल्यों पर आसानी से पुनरावृति कर सकता हूं?

कृपया इस सवाल पर ध्यान केंद्रित करें: मैं लूप के लिए रेंज में ऑटो और& का उपयोग क्यों करना चाहूंगा?


4
क्या आप वास्तव में इसे "अक्सर" देखते हैं?
ऑक्टेब

2
मुझे यकीन नहीं है कि आपके प्रश्न में मेरे लिए पर्याप्त संदर्भ है कि आप "पागल" को कैसे नापेंगे, जहां आप इसे देख रहे हैं।
दौड़

2
@LightnessRacesinOrbit लंबी कहानी छोटी: मैं auto&&छोरों के लिए रेंज-आधारित में क्यों उपयोग करना चाहूंगा ?
अली

जवाबों:


94

एकमात्र लाभ जो मैं देख सकता हूं, जब अनुक्रम पुनरावृत्त एक प्रॉक्सी संदर्भ देता है और आपको उस संदर्भ पर गैर-कॉन्स्टेबल तरीके से काम करने की आवश्यकता होती है। उदाहरण के लिए विचार करें:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    for (auto& e : v)
        e = true;
}

क्योंकि rvalue यह संकलन नहीं करता vector<bool>::referenceसे लौटे iteratorएक गैर स्थिरांक lvalue संदर्भ के लिए बाध्य नहीं होंगे। लेकिन यह काम करेगा:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    for (auto&& e : v)
        e = true;
}

कहा जा रहा है कि जब तक आप इस तरह के उपयोग के मामले को पूरा करने की जरूरत नहीं जानते, तब तक मैं इस तरह से कोड नहीं करूंगा। यानी मैं यह कृतज्ञतापूर्वक नहीं करूंगा क्योंकि यह लोगों को आश्चर्यचकित करता है कि आप क्या कर रहे हैं। और अगर मैंने ऐसा किया, तो टिप्पणी को शामिल करने के लिए इसे चोट नहीं पहुंचेगी:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    // using auto&& so that I can handle the rvalue reference
    //   returned for the vector<bool> case
    for (auto&& e : v)
        e = true;
}

संपादित करें

मेरा यह आखिरी मामला वास्तव में समझ बनाने के लिए एक टेम्पलेट होना चाहिए। यदि आप जानते हैं कि लूप हमेशा एक प्रॉक्सी संदर्भ को संभाल रहा है, तो autoसाथ ही साथ काम करेगा auto&&। लेकिन जब लूप कभी-कभी गैर-प्रॉक्सी संदर्भों और कभी-कभी प्रॉक्सी-संदर्भों को संभाल रहा auto&&होता है , तो मुझे लगता है कि पसंद का समाधान बन जाएगा।


3
दूसरी ओर, कोई स्पष्ट नुकसान नहीं है , वहाँ है? (संभावित रूप से भ्रमित करने वाले लोगों से, जो मुझे नहीं लगता कि व्यक्तिगत रूप से ध्यान देने योग्य है।)
ildjarn

7
कोड लिखने के लिए एक और शब्द जो अनावश्यक रूप से लोगों को भ्रमित करता है वह है: भ्रमित कोड लिखना। अपने कोड को यथासंभव सरल बनाना सबसे अच्छा है, लेकिन कोई सरल नहीं है। यह बग को नीचे रखने में मदद करेगा। जैसा कि कहा जा रहा है, जैसा कि && अधिक परिचित है, तो शायद अब से 5 साल बाद लोग एक ऑटो && मुहावरे की उम्मीद करेंगे (यह वास्तव में कोई नुकसान नहीं है)। मुझे नहीं पता कि ऐसा होगा या नहीं। लेकिन सरल देखने वाले की नज़र में है, और यदि आप केवल खुद से अधिक के लिए लिख रहे हैं, तो अपने पाठकों को ध्यान में रखें।
हावर्ड हिनान्ट

7
मैं पसंद करता हूं const auto&जब मैं चाहता हूं कि कंपाइलर मुझे यह जांचने में मदद करें कि मैं गलती से अनुक्रम में तत्वों को संशोधित नहीं करता हूं।
हावर्ड हिनान्ट

31
मैं व्यक्तिगत रूप auto&&से जेनेरिक कोड में उपयोग करना पसंद करता हूं जहां मुझे अनुक्रम के तत्वों को संशोधित करने की आवश्यकता है। अगर मैं नहीं, मैं बस से चिपके रहेंगे auto const&
Xeo

7
@ Xeo: +1 यह अपने आप में उत्साही लोगों की वजह से है, लगातार चीजों को करने के बेहतर तरीकों के लिए प्रयोग और धक्का देते हैं, ताकि C ++ का विकास जारी रहे। धन्यवाद। :-)
हावर्ड हिनान्ट

26

का उपयोग करना auto&&या सार्वभौमिक संदर्भ एक सीमा के आधार पर साथ for-loop आप कब्जा है कि आप क्या मिलता है लाभ दिया है। Iterators के सबसे प्रकार के लिए आप शायद या तो एक मिल जाएगा T&या T const&कुछ प्रकार के लिए T। दिलचस्प मामला यह है कि एक itter dereferencing से जहां एक अस्थायी पैदावार होती है: C ++ 2011 को आराम की आवश्यकताएं मिलीं और पुनरावृत्तियों के लिए पुनरावृत्तियों की आवश्यकता नहीं है। सार्वभौमिक संदर्भों का उपयोग तर्क अग्रेषण में मेल खाता है std::for_each():

template <typename InIt, typename F>
F std::for_each(InIt it, InIt end, F f) {
    for (; it != end; ++it) {
        f(*it); // <---------------------- here
    }
    return f;
}

समारोह वस्तु fइलाज कर सकते हैं T&, T const&और Tअलग ढंग से। रेंज-आधारित- forलूप का शरीर अलग क्यों होना चाहिए ? बेशक, वास्तव में लाभ लेने के लिए सार्वभौमिक संदर्भों का उपयोग करके टाइप करने के लिए आपको उन्हें इसी पर पास करना होगा:

for (auto&& x: range) {
    f(std::forward<decltype(x)>(x));
}

बेशक, उपयोग करने का std::forward()मतलब है कि आप किसी भी लौटाए गए मूल्यों को स्वीकार करते हैं। क्या इस तरह की वस्तुओं को गैर-टेम्पलेट कोड में बहुत अधिक समझ में आता है जो मुझे नहीं पता (अभी तक?)। मैं कल्पना कर सकता हूं कि सार्वभौमिक संदर्भों का उपयोग करके संकलक को राइट थिंग करने के लिए अधिक जानकारी प्रदान की जा सकती है। टेम्प्लेटेड कोड में यह ऑब्जेक्ट्स के साथ क्या होना चाहिए, इस पर कोई निर्णय लेने से बचता है।


9

मैं वास्तव में हमेशा उपयोग करता हूं auto&&। जब आपको नहीं करना है तो एक किनारे के मामले में क्यों काटें? यह भी टाइप करने के लिए छोटा है, और मैं बस इसे और अधिक ... पारदर्शी लगता है। जब आप उपयोग करते हैं auto&& x, तो आप जानते हैं कि xवास्तव में *it, हर बार।


29
मेरी समस्या यह है कि अगर आप constपीड़ित हैं auto&&तो आप हार मान रहे हैं const auto&। सवाल कोने के मामलों के लिए पूछता है जहां मुझे काट लिया जा सकता है। कौन से कोने के मामले हैं जिनका उल्लेख डिटमार या हॉवर्ड ने अभी तक नहीं किया है?
अली

2
यदि आप उपयोग करते हैं तो यहां काटे जाने का एक तरीका है auto&&। यदि आप जिस प्रकार पर कब्जा कर रहे हैं, उसे लूप के शरीर में स्थानांतरित किया जाना चाहिए (उदाहरण के लिए), और बाद की तारीख में बदल दिया जाता है, तो यह एक const&प्रकार का हल करता है , आपका कोड चुपचाप कार्य करना जारी रखेगा, लेकिन आपके कदम कॉपी आ जाएंगे। यह कोड बहुत भ्रामक होगा। यदि, हालांकि, आप स्पष्ट रूप से आर-मान संदर्भ के रूप में निर्दिष्ट करते हैं, तो जिस किसी ने भी कंटेनर प्रकार को बदल दिया है उसे संकलन त्रुटि मिलेगी क्योंकि आप वास्तव में चाहते थे कि ये वस्तुएं स्थानांतरित हो जाएं और नकल न की जाए ...
साइबरबॉन

@cyberbisson मैं अभी इस पर आया हूं: मैं स्पष्ट रूप से प्रकार निर्दिष्ट किए बिना एक संदर्भ संदर्भ कैसे लागू कर सकता हूं? कुछ पसंद है for (std::decay_t<decltype(*v.begin())>&& e: v)? मुझे लगता है कि एक बेहतर तरीका है ...
जेरी मा

@JerryMa यह आप पर निर्भर करता है क्या है प्रकार के बारे में पता है। जैसा कि ऊपर उल्लेख किया गया है, auto&&एक "सार्वभौमिक संदर्भ" देगा, इसलिए इसके अलावा कुछ भी आपको अधिक विशिष्ट प्रकार मिलेगा। अगर vमान लिया जाए कि vectorआप ऐसा कर सकते हैं decltype(v)::value_type&&, तो मैं वही कर सकता हूं जो आप operator*एक इटैलर प्रकार के परिणाम के आधार पर चाहते हैं। आप decltype(begin(v))::value_type&&कंटेनर के बजाय इट्रेटर के प्रकारों की जांच करने के लिए भी कर सकते हैं । यदि हम इस प्रकार में बहुत कम जानकारी रखते हैं, तो, हम इसे थोड़ा स्पष्ट समझ सकते हैं, बस साथ जाने के लिए auto&&...
साइबरबैसन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.