प्रस्तावना
जावा सी ++ की तरह कुछ भी नहीं है, प्रचार के विपरीत है। जावा प्रचार मशीन आपको विश्वास दिलाती है कि जावा में वाक्य रचना की तरह C ++ है, क्योंकि भाषाएं समान हैं। सच्चाई से कुछ भी दूर नहीं हो सकता। यह गलत सूचना इस कारण का कारण है कि जावा प्रोग्रामर C ++ में जाते हैं और अपने कोड के निहितार्थों को समझे बिना जावा जैसी सिंटैक्स का उपयोग करते हैं।
बाद में हम चलते हैं
लेकिन मैं यह पता नहीं लगा सकता कि हमें ऐसा क्यों करना चाहिए। मुझे लगता है कि इसे दक्षता और गति के साथ करना होगा क्योंकि हम स्मृति पते तक सीधे पहुंच प्राप्त करते हैं। क्या मैं सही हू?
इसके विपरीत, वास्तव में। ढेर की तुलना में बहुत धीमी है, क्योंकि ढेर ढेर की तुलना में बहुत सरल है। स्वचालित भंडारण चर (उर्फ स्टैक चर) उनके विध्वंसक होते हैं जिन्हें एक बार स्कोप से बाहर जाने पर बुलाया जाता है। उदाहरण के लिए:
{
std::string s;
}
// s is destroyed here
दूसरी ओर, यदि आप एक पॉइंटर को गतिशील रूप से आवंटित का उपयोग करते हैं, तो इसके विनाशकर्ता को मैन्युअल रूप से कहा जाना चाहिए। delete
आप के लिए इस विनाशकारी कहते हैं।
{
std::string* s = new std::string;
}
delete s; // destructor called
इसका new
C # और Java में मौजूद सिंटैक्स से कोई लेना-देना नहीं है । उनका उपयोग पूरी तरह से अलग उद्देश्यों के लिए किया जाता है।
गतिशील आवंटन के लाभ
1. आपको पहले से सरणी का आकार पता नहीं है
कई सी ++ प्रोग्रामर में चलने वाली पहली समस्याओं में से एक यह है कि जब वे उपयोगकर्ताओं से मनमाना इनपुट स्वीकार कर रहे हैं, तो आप केवल स्टैक चर के लिए एक निश्चित आकार आवंटित कर सकते हैं। आप सरणियों का आकार भी नहीं बदल सकते हैं। उदाहरण के लिए:
char buffer[100];
std::cin >> buffer;
// bad input = buffer overflow
बेशक, अगर आप std::string
इसके बजाय इस्तेमाल करते हैं, तो std::string
आंतरिक रूप से खुद को आकार देता है ताकि कोई समस्या न हो। लेकिन अनिवार्य रूप से इस समस्या का समाधान गतिशील आवंटन है। आप उदाहरण के लिए, उपयोगकर्ता के इनपुट के आधार पर डायनामिक मेमोरी आवंटित कर सकते हैं:
int * pointer;
std::cout << "How many items do you need?";
std::cin >> n;
pointer = new int[n];
साइड नोट : एक गलती जो कई शुरुआती करते हैं, वह चर लंबाई सरणियों का उपयोग है। यह एक GNU एक्सटेंशन है और क्लैंग में भी एक है क्योंकि वे GCC के कई एक्सटेंशन को मिरर करते हैं। तो निम्नलिखित
int arr[n]
पर भरोसा नहीं किया जाना चाहिए।
क्योंकि ढेर ढेर की तुलना में बहुत बड़ा है, कोई मनमाने ढंग से आवंटित कर सकता है / उतनी ही मेमोरी आवंटित कर सकता है जितनी उसे जरूरत है, जबकि स्टैक की एक सीमा है।
2. एरर्स पॉइंटर्स नहीं हैं
यह कैसा लाभ है जो आप पूछें? एक बार जब आप सरणियों और बिंदुओं के पीछे भ्रम / मिथक को समझ लेंगे तो उत्तर स्पष्ट हो जाएगा। यह आमतौर पर माना जाता है कि वे समान हैं, लेकिन वे नहीं हैं। यह मिथक इस तथ्य से आता है कि बिंदुओं को सरणियों की तरह ही सब्सक्राइब किया जा सकता है और क्योंकि फ़ंक्शन घोषणा में शीर्ष स्तर पर संकेत करने के लिए सरणियों के क्षय के कारण। हालाँकि, एक बार जब कोई पॉइंटर पॉइंटर पर जाता है, तो पॉइंटर अपनी sizeof
जानकारी खो देता है। तो sizeof(pointer)
बाइट्स में पॉइंटर का आकार देगा, जो आमतौर पर 64-बिट सिस्टम पर 8 बाइट्स होता है।
आप सरणियों को असाइन नहीं कर सकते हैं, केवल उन्हें इनिशियलाइज़ कर सकते हैं। उदाहरण के लिए:
int arr[5] = {1, 2, 3, 4, 5}; // initialization
int arr[] = {1, 2, 3, 4, 5}; // The standard dictates that the size of the array
// be given by the amount of members in the initializer
arr = { 1, 2, 3, 4, 5 }; // ERROR
दूसरी तरफ, आप पॉइंटर्स के साथ जो चाहें कर सकते हैं। दुर्भाग्य से, क्योंकि पॉइंटर्स और सरणियों के बीच अंतर को जावा और सी # में लहराया जाता है, शुरुआती लोग अंतर को नहीं समझते हैं।
3. बहुरूपता
जावा और सी # में ऐसी सुविधाएं हैं जो आपको उदाहरण के लिए as
कीवर्ड का उपयोग करके वस्तुओं को दूसरे के रूप में व्यवहार करने की अनुमति देती हैं । इसलिए अगर कोई किसी Entity
वस्तु को एक वस्तु के रूप में मानना चाहता है, तो कोई Player
ऐसा कर सकता है Player player = Entity as Player;
यदि आप एक सजातीय कंटेनर पर कार्यों को कॉल करने का इरादा रखते हैं जो केवल एक विशिष्ट प्रकार पर लागू होना चाहिए। कार्यक्षमता नीचे एक समान तरीके से प्राप्त की जा सकती है:
std::vector<Base*> vector;
vector.push_back(&square);
vector.push_back(&triangle);
for (auto& e : vector)
{
auto test = dynamic_cast<Triangle*>(e); // I only care about triangles
if (!test) // not a triangle
e.GenericFunction();
else
e.TriangleOnlyMagic();
}
तो यह कहें कि यदि केवल त्रिभुजों में एक रोटेट फ़ंक्शन होता है, तो यह एक संकलक त्रुटि होगी यदि आपने इसे कक्षा के सभी ऑब्जेक्ट पर कॉल करने का प्रयास किया। का उपयोग करके dynamic_cast
, आप as
कीवर्ड का अनुकरण कर सकते हैं । स्पष्ट होने के लिए, यदि कोई कलाकार विफल रहता है, तो वह एक अमान्य सूचक लौटाता है। तो !test
अनिवार्य रूप से जाँच के लिए एक शॉर्टहैंड है यदि test
NULL या अमान्य पॉइंटर है, जिसका अर्थ है कि कलाकार विफल हो गया है।
स्वचालित चर का लाभ
सभी महान चीजों को देखने के बाद गतिशील आवंटन कर सकते हैं, आप शायद सोच रहे हैं कि कोई भी हर समय गतिशील आवंटन का उपयोग क्यों नहीं करेगा? मैंने आपको पहले से ही एक कारण बताया था, ढेर धीमा है। और अगर आपको उस सभी मेमोरी की आवश्यकता नहीं है, तो आपको इसका दुरुपयोग नहीं करना चाहिए। तो यहाँ कोई विशेष क्रम में कुछ नुकसान हैं:
यह त्रुटि-प्रवण है। मैनुअल मेमोरी आवंटन खतरनाक है और आपको लीक होने का खतरा है। यदि आप डीबगर या valgrind
(मेमोरी लीक टूल) का उपयोग करने में कुशल नहीं हैं , तो आप अपने सिर से अपने बालों को खींच सकते हैं। सौभाग्य से RAII मुहावरे और स्मार्ट पॉइंटर्स इसे थोड़ा कम करते हैं, लेकिन आपको द रूल ऑफ थ्री और द रूल ऑफ फाइव जैसी प्रथाओं से परिचित होना चाहिए। यह बहुत सारी जानकारी है, और शुरुआती लोगों को जो या तो नहीं जानते हैं या परवाह नहीं करते हैं, इस जाल में पड़ जाएंगे।
यह आवश्यक नहीं है। जावा और C # के विपरीत, जहाँ new
C ++ में हर जगह कीवर्ड का उपयोग करना मुहावरेदार है , आपको इसका उपयोग केवल तभी करना चाहिए जब आपको आवश्यकता हो। सामान्य वाक्यांश, सब कुछ एक कील की तरह दिखता है यदि आपके पास एक हथौड़ा है। जबकि C ++ से शुरू होने वाले शुरुआती लोग पॉइंटर्स से डरते हैं और आदत से स्टैक चर का उपयोग करना सीखते हैं, जावा और सी # प्रोग्रामर बिना समझे पॉइंटर्स का उपयोग करके शुरू करते हैं! यह सचमुच गलत पैर पर कदम है। आपको वह सब कुछ छोड़ देना चाहिए जो आप जानते हैं क्योंकि वाक्य रचना एक चीज है, भाषा सीखना एक और बात है।
1. (एन) आरवीओ - एका, (नामांकित) रिटर्न वैल्यू ऑप्टिमाइज़ेशन
एक अनुकूलन कई संकलक बनाते हैं जो कि चीरा और वापसी मूल्य अनुकूलन नामक चीजें हैं । ये चीजें अनावश्यक कॉपियों को समाप्त कर सकती हैं जो उन वस्तुओं के लिए उपयोगी होती हैं जो बहुत बड़ी हैं, जैसे कि एक वेक्टर जिसमें कई तत्व होते हैं। आम तौर पर आम बात यह है कि बड़े ऑब्जेक्ट्स को चारों ओर ले जाने के लिए कॉपी करने के बजाय स्वामित्व का हस्तांतरण करने के लिए पॉइंटर्स का उपयोग करें। इससे चाल शब्दार्थ और स्मार्ट संकेत की शुरुआत हुई है ।
यदि आप पॉइंटर्स का उपयोग कर रहे हैं, तो (एन) आरवीओ नहीं होता है। यदि आप अनुकूलन के बारे में चिंतित हैं, तो लौटने या पास होने के बजाय (एन) आरवीओ का लाभ लेने के लिए यह अधिक फायदेमंद और कम त्रुटि वाला है। त्रुटि लीक तब हो सकती है जब किसी फ़ंक्शन का कॉलर delete
डायनामिक रूप से आवंटित ऑब्जेक्ट और इस तरह से करने के लिए ज़िम्मेदार हो । किसी वस्तु के स्वामित्व को ट्रैक करना मुश्किल हो सकता है यदि गर्म आलू की तरह पॉइंटर्स को पास किया जा रहा है। बस स्टैक चर का उपयोग करें क्योंकि यह सरल और बेहतर है।