c++ क्या आप उन सभी चरों को चिह्नित करने में कोई कमी कर रहे हैं जिन्हें आपने कास्ट संशोधित नहीं किया है?




refactoring const (6)

मुझे पता है कि इस तरह के एक छोटे, सरल उदाहरण से वास्तव में कोई बड़ा लाभ नहीं दिखता है, लेकिन ऐसा लगता है कि यह एक बड़े कोडबेस में मददगार होगा जहां आप गलती से एक चर को म्यूट कर सकते हैं जिसे आपको म्यूट नहीं करना चाहिए।

समस्या यह है कि यह मूल रूप से वास्तव में कभी नहीं होता है।

दूसरी ओर, const एक बीमारी है जो प्लेग की तरह आपके कोडबेस से फैल जाएगी । जैसे ही आप एक const वैरिएबल घोषित करते हैं, उस पर आपके लिए आवश्यक सभी चीजें const होनी चाहिए, और इसलिए उन्हें केवल const फ़ंक्शंस को कॉल करना होगा, और यह कभी भी बंद नहीं होगा।

const दूर से उस मूल्य के लायक नहीं है जो आप इसके लिए विभिन्न स्थितियों में देते हैं। केवल कुछ मामलों में जहां const वास्तव में आपकी रक्षा करता है (उदाहरण के लिए सेट कीज़), लेकिन फिर भी, यह बहस का विषय है कि अगर आपको पहले स्थान पर प्रयास करने के लिए कुल मोर्टन होना चाहिए, और शायद सभी भाषा नियमों और लायक नहीं हैं निरंतर कोड दोहराव और निरर्थक मेटलोगिक।

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

https://code.i-harness.com

बहुत सारे गुग्लिंग के बाद मैंने फ़ंक्शंस और उनके मापदंडों को const रूप में चिह्नित करने के बारे में बहुत कुछ पाया है, लेकिन वैरिएबल को const रूप में चिह्नित करने पर कोई मार्गदर्शक नहीं है।

यहाँ एक बहुत सरल उदाहरण है:

#include <string>
#include <iostream>

void example(const std::string& x) {
  size_t length = x.length();
  for (size_t i = 0; i < length; ++i) {
    std::cout << x.at(i) << std::endl;
  }
}

int main() {
  example("hello");
}

क्यों नहीं बनाते?

size_t length = x.length();

कास्ट की तरह

const size_t length = x.length();

रिवाज के अनुसार?

मुझे पता है कि इस तरह के एक छोटे, सरल उदाहरण से वास्तव में कोई बड़ा लाभ नहीं दिखता है, लेकिन ऐसा लगता है कि यह एक बड़े कोडबेस में मददगार होगा जहां आप गलती से एक चर को म्यूट कर सकते हैं जिसे आपको म्यूट नहीं करना चाहिए।

उस लाभ के बावजूद, मैं वास्तव में इसे बहुत ज्यादा इस्तेमाल नहीं करता (सी ++ कोडबेस में मैंने देखा है) या लगभग फ़ंक्शन और उनके मापदंडों को बनाने के रूप में ज्यादा उल्लेख किया है।

वहाँ 5 अतिरिक्त अक्षर टाइप करने के अलावा यह करने के लिए कुछ नकारात्मक है? मुझे इस विषय पर बहुत कुछ नहीं मिला है, और अगर मुझे इतने सारे कॉन्स्टेक्ट होने की समस्या है तो मैं खुद को पैर में गोली नहीं मारना चाहता।


इसके बजाय ofnon- मानक कोड:

#import <string>
#import <iostream>

void example(const std::string& x) {
  size_t length = x.length();
  for (size_t i = 0; i < length; ++i) {
    std::cout << x.at(i) << std::endl;
  }
}

int main() {
  example("hello");
}

... मैं इसे लिखूंगा:

#include <string>
#include <iostream>
using namespace std;

void example( string const& s )
{
    for( char const ch : s )
    {
        cout << ch << '\n';
    }
}

auto main()
    -> int
{ example( "hello" ); }

मुख्य कोड जिसे मैं जोड़ सकता था, मूल कोड के सापेक्ष, लूप में ch चर के लिए था। मुझे लगता है कि यह अच्छा है। const आम तौर पर वांछनीय है क्योंकि यह संभावित कोड क्रियाओं को कम करता है जिस पर विचार करना है, और रेंज आधारित लूप आपको अधिक const

अधिकांश चीजों के लिए const का उपयोग करने का मुख्य दोष यह है कि जब आपको सी एपीआई से संबंधित होना है।

फिर किसी को डेटा को कॉपी करने, या दस्तावेज़ीकरण पर भरोसा करने और एक const_cast उपयोग करने के बारे में कुछ आंतों का निर्णय करना const_cast

परिशिष्ट 1:
ध्यान दें कि रिटर्न प्रकार पर const शब्दार्थ को रोकता है। जहाँ तक मुझे पता है कि यह पहली बार आंद्रेई अलेक्जेंड्रेस्कु द्वारा अपने मोजो (C ++ 03 चाल शब्दार्थ) में डॉ। डॉब्स जर्नल में लिखा गया था:

[A] const अस्थाई const की तरह दिखता है, जो शब्दों में विरोधाभास है। एक व्यावहारिक दृष्टिकोण से देखा जाए, तो const अस्थायी रूप से गंतव्य पर नकल करते हैं।

तो, यह एक जगह है जहां एक const उपयोग नहीं करना चाहिए।

क्षमा करें कि मैं इसका मूल रूप से उल्लेख करना भूल गया; मुझे एक और उत्तर पर उपयोगकर्ता बोगदान की टिप्पणी द्वारा याद दिलाया गया था।

परिशिष्ट 2:
एक ही नस में (गतिमान अर्थ विज्ञान का समर्थन करने के लिए), अगर किसी औपचारिक तर्क के साथ किया गया आखिरी काम कहीं प्रति को संग्रहीत करना है, तो const संदर्भ में पारित होने के बजाय मूल्य से पारित एक गैर- const तर्क का उपयोग करना बेहतर हो सकता है, क्योंकि यह बस से स्थानांतरित किया जा सकता है।

यानी, के बजाय

string stored_value;

void foo( string const& s )
{
    some_action( s );
    stored_value = s;
}

... या अनुकूलित की अतिरेक

string stored_value;

void foo( string const& s )
{
    some_action( s );
    stored_value = s;
}

void foo( string&& s )
{
    some_action( s );
    stored_value = move( s );
}

... सिर्फ लिखने पर विचार करें

string stored_value;

void foo( string s )
{
    some_action( s );
    stored_value = move( s );
}

लैवल्यू वास्तविक तर्क के मामले के लिए यह थोड़ा कम कुशल हो सकता है, यह const के फायदों का const (कोड क्या कर सकता है इस पर अड़चनें), और यह जहां भी संभव हो, const का उपयोग करने का एक समान सम्मेलन तोड़ देता है, लेकिन यह बुरी तरह से प्रदर्शन नहीं करता है किसी भी स्थिति में (जो कि मुख्य लक्ष्य है, उससे बचने के लिए) और यह छोटा और संभवतः अधिक स्पष्ट कोड है।

नोट :
¹ मानक C ++ में #import निर्देश नहीं है। इसके अलावा, उन हेडर, जब ठीक से शामिल किए गए हैं, वैश्विक नामस्थान में size_t को परिभाषित करने की गारंटी नहीं है।


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

अधिक लंबी या अधिक जटिल विधि के लिए, यह अलग हो सकता है। लेकिन फिर, यदि आपके पास इतनी जटिल विधि है कि यह मायने रखता है, तो शायद आपको कम से कम अपने कोड को सरल टुकड़ों में रिफ्लेक्ट करने पर विचार करना चाहिए ... वैसे भी, यदि आप कोड को पढ़ते हैं और समझते हैं, तो स्पष्ट const द्वारा प्रदान किया गया अतिरिक्त संकेत थोड़े अप्रासंगिक है - अच्छा लेकिन अप्रासंगिक।

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


ऐसे वेरिएबल को चिन्हित करने के लिए कोई डाउनसाइड नहीं है, जिन्हें आप const संशोधित नहीं करते हैं।

हालांकि कुछ अप-साइड्स हैं: कंपाइलर आपको तब निदान करने में मदद करेगा जब आप अनजाने में एक वैरिएबल को संशोधित करेंगे, जिसका आपको कोई मतलब नहीं होना चाहिए / नहीं था और कंपाइलर हो सकता है (हालाँकि भाषा const_cast और const_cast होने के कारण यह दुर्लभ है) बेहतर उत्पन्न करता है कोड।

तो, मैं सलाह देता हूं; जहाँ आप कर सकते हैं का उपयोग करें। कोई डाउनसाइड नहीं है और आपका कंपाइलर संभावित रूप से बग्स को स्पॉट करने में आपकी मदद कर सकता है। कोई कारण नहीं (कुछ अतिरिक्त टाइपिंग को छोड़कर)।

ध्यान दें कि यह सदस्य के रूप में अच्छी तरह से कार्य करता है। जब आप कर सकते हैं तो उन्हें const करें - यह उन्हें अधिक संदर्भों में उपयोग करने देता है और उपयोगकर्ताओं को कोड के बारे में कारण में मदद करता है ("इस फ़ंक्शन को कॉल करना ऑब्जेक्ट को संशोधित नहीं करेगा" मूल्यवान जानकारी है)।


मैं अब तक दिए गए अधिकांश उत्तरों से सहमत हूं, दूसरी ओर, कुछ पहलू अभी भी गायब हैं।

इंटरफेस को परिभाषित करते समय, const कीवर्ड आपका दोस्त है। लेकिन आपको पता होना चाहिए कि यह कुछ हद तक सीमित है और कभी-कभी अहंकारी भी होता है - यही मैं इसके पतन को कहूंगा।

चलो प्रश्न पर एक और करीबी नज़र रखते हैं :

क्या सभी चर को चिह्नित करने के लिए कोई डाउनसाइड है जो आप कास्ट को संशोधित नहीं करते हैं? `

यदि आप देखते हैं कि आप कुछ संशोधित नहीं करते हैं, तो आप कह सकते हैं कि यह प्रभावी रूप से स्थिर है। इसके अलावा कोड विश्लेषण उपकरण यह पता लगा सकते हैं, यहां तक ​​कि आपके कंपाइलर को भी यह पता चल जाएगा। लेकिन इस अवलोकन को आप में ऐड-कास्ट रिफ्लेक्स को ट्रिगर नहीं करना चाहिए।

इसके बजाय स्वयं चर के बारे में सोचें, पूछें

  • क्या यह बिल्कुल उपयोगी है?
  • क्या यह भी स्थिर रहने का इरादा है?

कभी-कभी एक मध्यवर्ती चर को केवल हटाया जा सकता है, कभी-कभी कोड को बेहतर बनाने के लिए एक छोटे से काम (एक समारोह को जोड़ना या निकालना) किया जा सकता है।

const कीवर्ड जोड़ने से आपका कोड कहीं और त्रुटियों के खिलाफ कठोर हो सकता है, लेकिन घोषणा बिंदु पर बदलाव के खिलाफ भी।

मुझे सदस्य चर के बारे में एक शब्द भी जोड़ना है जो नहीं बदलते हैं। यदि आप एक सदस्य चर const घोषित करने का निर्णय लेते हैं, तो आपको इसे युक्त वर्ग के निर्माता की इनिशियलाइज़र सूची में आरंभीकृत करना होगा, यह इस वर्ग की वस्तुओं के निर्माण के लिए पूर्व शर्त का विस्तार करता है।

जहां भी आपका कंपाइलर इसके लिए अनुमति देता है, वहां const न जोड़ें। "अपने कोड को शांत करने के लिए" बहकावा मत बनो; ;-)


मैं कम से कम दो डाउनसाइड के बारे में सोच सकता हूं:

  • क्रिया: अधिक शब्द, प्रक्रिया के लिए और अधिक प्रतीक, ...
  • जड़ता: यदि आपको इसे संशोधित करने की आवश्यकता है, तो आपको इस const दूर करना होगा

और दोनों इसके लायक हैं।

वर्बोसिटि गवाह के खिलाफ अक्सर सुना जाने वाला तर्क है, हालांकि लोग अक्सर समझने की गति के साथ पढ़ने की गति में गलती करते हैं। वर्बोसिटी और एक्सप्लोसिव के बीच पाया जाने वाला एक संतुलन है, निश्चित रूप से, बहुत अधिक क्रिया उपयोगी जानकारी को बाहर निकाल सकती है, लेकिन बहुत ही निहित / छंद जानकारी को प्रस्तुत नहीं कर सकती है जिसे पुनर्निर्माण / अनुमान / घटाया / किया जाना है।

निजी तौर पर, मैं दृढ़ता से टाइप की गई भाषा का उपयोग करता हूं ताकि कंपाइलर मेरी गलती को जल्द से जल्द पूरा कर सके; const साथ एनोटेट करना पाठक और कंपाइलर दोनों को जानकारी दे रहा है। मैं इसे अतिरिक्त 6 प्रतीकों के लायक समझता हूं।

जड़ता के रूप में, कास्ट को हटाना संभवतः परिवर्तन की केवल एक छोटी सी लागत है ... और यह आपको स्वयं को सभी जगहों से गुजरने के लिए मजबूर करता है जहां इसका उपयोग किया जाता है और आसपास के कोड की समीक्षा करके यह सुनिश्चित करना है कि यह वास्तव में इस const को हटाने के लिए ठीक है। एक कोड पथ में अचानक एक विशेष डेटा को संशोधित करना जहां वह पहले अपरिवर्तनीय था, यह सुनिश्चित करने की आवश्यकता है कि कोड पथ (या इसके कॉलर्स) का कोई भी हिस्सा गलती से इस अपरिवर्तनीयता पर निर्भर न हो।







const