c++ क्या यह कास्ट ऑटो और बेमानी नहीं है?




const (7)

मुझे यह कोड स्ट्रॉस्ट्रुप की पुस्तकों में से एक में मिला:

void print_book(const vector<Entry>& book)
{
     for (const auto& x : book) // for "auto" see §1.5
           cout << x << '\n';
}

लेकिन const_iterator बेमानी लगता है क्योंकि x const_iterator होने के कारण x const_iterator क्योंकि book पैरामीटर में है। क्या const auto वास्तव में बेहतर है?

https://code.i-harness.com


कोड सिर्फ पढ़ने के लिए संकलक के लिए नहीं है - यह मनुष्यों के पढ़ने के लिए भी है। पठनीयता की कीमत पर नहीं आने पर चिंता केवल अच्छी है।

दिए गए कोड में, निरंतर कब्ज तत्काल है। आपके प्रस्तावित बदलाव के साथ, निरंतरता में कटौती करने से पाठक को book की परिभाषा को सही ढंग से याद रखने या उसकी समीक्षा करने की आवश्यकता होगी।

यदि पाठक का इरादा कब्ज के बारे में पता होना है, तो संक्षिप्तता यहाँ प्रतिशोधात्मक होगी।


जल्दी से उल्लेख करना और अक्सर कोड के पाठक को इस बारे में अधिक बताता है कि पाठक के बिना क्या चल रहा है और कोड में और अधिक दूर देखने के लिए।

अब, आपका कोड दिया गया है, मैं इसे लिखूंगा:

void print_book(const std::vector<Entry>& book)
{
  for (auto&& x : book)
     std::cout << x << '\n';
}

या और भी:

void print_book(std::experimental::array_view<const Entity> book)
{
  for (auto&& x : book)
     std::cout << x << '\n';
}

लेकिन केवल इसलिए कि कोड बहुत कम है, मैं निरर्थक const छोड़ const

( array_view संस्करण एक vector - vector<?> const& तर्क पर बेकार निर्भरता को हटाता है; आमतौर पर vector<?> const& रूप में आपके इंटरफ़ेस को निर्दिष्ट करता है; vector<?> const& उपयोगी कुछ भी नहीं प्रदान करता है जो array_view<?> प्रदान नहीं करता है, फिर भी? प्रारंभिक सूचियों से या कच्ची सी सरणियों या जैसे से प्रतियां कॉपी करें।)

जहां तक ​​संकलक का संबंध है, वहां const auto& ओवर auto& या const auto& का उपयोग करने का कोई कारण नहीं है, क्योंकि सभी 3 (इस संदर्भ में) एक ही प्रकार के होने के लिए कटौती की जाती है। एक या दूसरे का उपयोग करने का एकमात्र कारण अन्य प्रोग्रामर से बात करना है

मेरे मामले में, मैं डिफ़ॉल्ट रूप से auto&& उपयोग करता हूं (यह कहता है कि मैं पुनरावृत्ति कर रहा हूं, और वास्तव में मुझे परवाह नहीं है कि मैं इससे अधिक क्या कर रहा हूं)।

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


मेरी राय में, यह स्पष्ट है कि यह बेहतर क्यों है। इसलिए अगर मेरा मतलब है, तो मैं इसे स्पष्ट रूप से लिखना चाहूंगा। यह स्थानीय तर्क को बढ़ाता है और इस प्रकार दूसरों को तुलनात्मक रूप से आसानी से कोड को समझने में मदद करता है - अन्य प्रोग्रामर को book की घोषणा को देखने की जरूरत नहीं है और अनुमान लगाया है कि x const भी है।


मैं एक काउंटर-पॉइंट की पेशकश करना चाहता हूं। CppCon 2014 में हर्ब सटर की बात "बैक टू द बेसिक्स! आधुनिक सी ++ शैली की अनिवार्यता" (टाइमस्टैम्प 34:50), वह इस उदाहरण को दर्शाता है:

void f( const vector<int>& v) {
  vector<int>::iterator i = v.begin();       // error
  vector<int>::const_iterator i = v.begin(); // ok + extra thinking
  auto i = v.begin();                        // ok default

उनका तर्क है कि फ़ंक्शन के पैरामीटर को बदलने पर भी auto बस काम करेगा, क्योंकि यह सही ढंग से कांस्ट या non-const । आगे स्लाइड 36 पर, उन्होंने कहा "आपको पता होना चाहिए कि आपका वैरिएबल कांस्टेबल / वाष्पशील है या नहीं!" स्थानीय चर के लिए "ऑटो और&" क्यों खराब है, इसके लिए तर्क के रूप में।

अनिवार्य रूप से यह राय के मामले में उबलता है। कुछ लोग सोचते हैं कि स्पष्ट होना पठनीयता या स्थिरता के लिए अच्छा है, लेकिन इसके विपरीत तर्क दिया जा सकता है: निरर्थक होना समझ की कमी दर्शाता है (या तो C ++ नियमों या आपका कोड वास्तव में 1 क्या कर रहा है) और पठनीयता और स्थिरता को नुकसान पहुंचा सकता है। जो आपको अच्छा लगे, वही करें।

1 : यह एक अधिक स्पष्ट उदाहरण है, लेकिन C ++ के नियम वास्तव में सामान्य स्थिति में काम नहीं करते हैं और याद रखना कठिन हैं। उदाहरण के लिए, हर्ब सटर की सिफारिश की गई है कि आपके पास नियमित रूप से कार्य अधिभार के विपरीत निर्माता पैरामीटर पास हैं। यह उन स्थितियों में से एक है जहां हर जगह कांस्ट आपको पैर में काट सकता है, यह इस बात पर निर्भर करता है कि आप हर्ब से सहमत हैं या नहीं।


मैं यहां एक अलग कोण लेने जा रहा हूं। const और const_iterator मतलब पूरी तरह से अलग चीजें हैं।

const लागू const अर्थ है कि आप पुनरावृत्ति को स्वयं संशोधित नहीं कर सकते हैं, लेकिन आप उस तत्व को संशोधित कर सकते हैं, जो int* const तरह एक पॉइंटर घोषित किया गया है। const_iterator मतलब है कि आप उस तत्व को संशोधित नहीं कर सकते हैं जो इसे इंगित करता है, लेकिन आप अभी भी const_iterator को स्वयं संशोधित कर सकते हैं (यानी। आप इसे const_iterator सकते हैं और इसे const_iterator सकते हैं) जैसे कि एक संकेतक जैसे कि const int*

std::vector<int> container = {1, 2, 3, 4, 5};
const std::vector<int> const_container = {6, 7, 8, 9, 0};
auto it1 = container.begin();
const auto it2 = container.begin();
auto it3 = const_container.begin();
const auto it4 = const_container.begin();

*it1 = 10; //legal
*it2 = 11; //legal
*it3 = 12; //illegal, won't compile
*it4 = 13; //illegal, won't compile

it1++; //legal
it2++; //illegal, won't compile
it3++; //legal
it4++; //illegal, won't compile

जैसा कि आप देख सकते हैं, तत्व को संशोधित करने की क्षमता const_iterator अंक केवल इस बात पर निर्भर करता है कि क्या यह एक const_iterator या const_iterator , और const_iterator को संशोधित करने की क्षमता केवल इस बात पर निर्भर करती है कि क्या const_iterator लिए चर घोषणा में एक const qualifier है।

संपादित करें: मुझे सिर्फ यह महसूस हुआ कि यह एक सीमा है और इसलिए यहाँ खेलने वालों का कोई मतलब नहीं है (कम से कम स्पष्ट रूप से नहीं)। x एक इटरेटर नहीं है और वास्तव में कंटेनर के एक तत्व का सीधा संदर्भ है। लेकिन आपके पास सही विचार है, यह इस बात की परवाह किए बिना कि क्या स्पष्ट रूप से लिखा गया है, const क्वालिफायर होने के लिए घटाया जाएगा।


यह कीवर्ड const देखकर बहुत स्पष्ट है। आप तुरंत पहचान लेते हैं कि यह संशोधित नहीं होने जा रहा है, अगर const कीवर्ड नहीं था तो हमें पता नहीं चलता जब तक कि हम फंक्शन सिग्नेचर को नहीं देख लेते।

कोड के पाठकों के लिए स्पष्ट रूप से const कीवर्ड का उपयोग करना बेहतर है।

इसके अलावा, जब आप नीचे दिए गए कोड को पढ़ते हैं, तो आपको लगता है कि x परिवर्तनीय है

for (auto& x : book) { ... }

और फिर जब आप x को संशोधित करने का प्रयास करते हैं, तो आप पाएंगे कि यह एक त्रुटि के कारण है क्योंकि book की const
यह मेरी राय में स्पष्ट कोड नहीं है। कोड में यह बताना बेहतर है कि x को संशोधित नहीं किया जाएगा ताकि अन्य जो कोड पढ़ते हैं, उनकी अपेक्षाएं सही होंगी।


यह विशिष्ट उदाहरण काफी सरल है, क्योंकि इनपुट ऐरे को कास्ट के रूप में घोषित किया गया है। सामान्य तौर पर, दोनों डेवलपर के लिए राउंड-बेस्ड में const का उपयोग करना उपयोगी हो सकता है (यदि वह कंटेनर को संशोधित करने की कोशिश करता है तो उसे संकलक त्रुटि मिलेगी) और संकलक के लिए (स्पष्ट const कभी-कभी कोड को अनुकूलित करने में मदद करता है)







const