ट्रैक
/
C++
C++
/
अभ्यास
/
ट्रॉय की शक्ति
ट्रॉय की शक्ति

ट्रॉय की शक्ति

सीखने का अभ्यास

परिचय

C++ में auto कीवर्ड

C++ में auto कीवर्ड एक शक्तिशाली सुविधा है, जिसे C++11 में जोड़ा गया था। इसका उपयोग ऐसे वेरिएबल घोषित करने के लिए किया जाता है जिनका डेटा टाइप अनुमान से तय होता है। कंपाइलर वेरिएबल का टाइप उसके इनिशियलाइज़र के आधार पर अनुमान लगाता है, जिससे कोड पढ़ने में आसान और बनाए रखने में सरल हो जाता है।

उपयोग का उदाहरण

नीचे दिए गए उदाहरण को देखिए, जिसमें auto का उपयोग वेरिएबल घोषित करने के लिए किया गया है:

auto dragon_population{3};          // dragon_population is deduced as an integer
auto westeros{7.7777};              // westeros is deduced as a double
auto wedding_location{"The Twins"}; // wedding_location is deduced as a const char*, not std::string

हर मामले में वेरिएबल का टाइप उस वैल्यू से तय होता है जिससे उसे इनिशियलाइज़ किया जाता है।

टाइप अनुमान

auto कीवर्ड स्पष्ट रूप से लिखे गए टाइपों की लंबाई घटाकर कोड को छोटा और पढ़ने में आसान बनाने में मदद करता है।

const std::vector<std::string> pigeon_pie{"flour", "butter", "pigeon", "salt"};
auto purple_wedding_pie{pigeon_pie};
purple_wedding_pie.emplace_back("the strangler");

इस लूप में auto purple_wedding_pie का टाइप std::vector<std::string> मान लेता है, जिससे टाइप को फिर से स्पष्ट रूप से लिखने की ज़रूरत नहीं पड़ती।

अनुकूलता

auto कीवर्ड C++ की कई चीज़ों के साथ काम करता है, जिससे यह आधुनिक C++ प्रोग्रामिंग में एक बहुमुखी टूल बन जाता है।

auto& element{array[0]};           // reference to an element
const auto object{otherObject};    // const type version of otherObject's type
auto* ptr{&x};                     // pointer to x with the same type as x, but as a pointer.

आगे के कॉन्सेप्ट में हम auto कीवर्ड को लैम्ब्डा एक्सप्रेशन, रेंज-बेस्ड for लूप और इटरेटर के साथ अक्सर देखेंगे।

स्मार्ट पॉइंटर

स्मार्ट पॉइंटर आधुनिक C++ की एक सुविधा है, जो अपने आप मेमोरी मैनेजमेंट करने के लिए बनाई गई है। यह मेमोरी लीक और डैंगलिंग पॉइंटर रोकने में मदद करती है, जो आम तौर पर रॉ पॉइंटर के साथ जुड़े होते हैं। ये रॉ पॉइंटर के चारों ओर रैपर की तरह काम करते हैं और अतिरिक्त सुविधाएँ जोड़ते हैं, जैसे पॉइंटर की ज़रूरत खत्म होने पर मेमोरी अपने आप मुक्त कर देना।

सामान्य सिंटैक्स

स्मार्ट पॉइंटर आम तौर पर C++ स्टैंडर्ड लाइब्रेरी में क्लास टेम्पलेट के रूप में लागू किए जाते हैं। सबसे ज़्यादा इस्तेमाल होने वाले दो स्मार्ट पॉइंटर std::unique_ptr और std::shared_ptr हैं।

यूनीक पॉइंटर

std::unique_ptr एक स्मार्ट पॉइंटर है जो ऑब्जेक्ट का अकेला मालिक होता है। यह सुनिश्चित करता है कि किसी भी समय सिर्फ एक ही std::unique_ptr ऑब्जेक्ट उस रिसोर्स का मालिक हो। जब मालिक std::unique_ptr नष्ट या रीसेट होता है, तो यह ऑब्जेक्ट को अपने आप नष्ट कर देता है और उसकी मेमोरी मुक्त कर देता है।

#include <memory>
// Declaring and defining a unique pointer
auto rightful_king_of_england = std::make_unique<std::string>("Excalibur");

// Unique pointers cannot be copied or assigned
auto mordred = rightful_king_of_england; // Error: Cannot copy a unique_ptr

std::make_unique() के फायदे

std::unique_ptr बनाते समय मेमोरी देने के लिए सीधे new इस्तेमाल करने की बजाय std::make_unique() का उपयोग करना बेहतर होता है। std::make_unique() कई फायदे देता है:

  1. एक्सेप्शन से सुरक्षा: std::make_unique() एक्सेप्शन से सुरक्षा की गारंटी देता है। अगर ऑब्जेक्ट बनाते समय कोई एक्सेप्शन आता है, तो मेमोरी अपने आप मुक्त हो जाएगी और मेमोरी लीक नहीं होगी।
  2. स्पष्टता: std::make_unique() इस्तेमाल करने से कोड ज़्यादा साफ और छोटा हो जाता है। इससे आवंटित किए जाने वाले टाइप को स्पष्ट रूप से लिखने की ज़रूरत खत्म हो जाती है, क्योंकि टेम्पलेट आर्गुमेंट अपने आप तय हो जाते हैं।
  3. बेहतर अनुकूलन के अवसर: कंपाइलर new से हाथ से मेमोरी देने की तुलना में std::make_unique() का ज़्यादा अच्छी तरह अनुकूलन कर सकते हैं, जिससे परफॉर्मेंस बेहतर हो सकती है।
  4. गलत इस्तेमाल से बचाव: जब std::unique_ptr हाथ से बनाया जाता है, तो उसके नीचे के रिसोर्स को डिलीट करना संभव होता है। जब std::unique_ptr स्कोप के अंत में उसे डिलीट करने की कोशिश करता है, तो इससे अनडिफाइंड बिहेवियर हो सकता है।

शेयर्ड पॉइंटर

std::shared_ptr एक स्मार्ट पॉइंटर है जो कई std::shared_ptr ऑब्जेक्ट को एक ही रिसोर्स का मालिकाना साझा करने देता है। यह ध्यान रखता है कि कितने शेयर्ड पॉइंटर उस रिसोर्स को इस्तेमाल कर रहे हैं, और मेमोरी तभी मुक्त करता है जब रिसोर्स का मालिक अंतिम शेयर्ड पॉइंटर स्कोप से बाहर जाता है या रीसेट होता है।

// Declaring and defining a shared pointer to a dynamically allocated string
auto martian_congressional_republic = std::make_shared<std::string>("protomolecule");

// Creating more shared pointer that shares ownership
auto outer_planets_alliance = martian_congressional_republic;
auto united_nations = martian_congressional_republic;
Caution

C++17 और उससे पहले के वर्शन में std::shared_ptr को std::make_shared<T[]> के ज़रिए ऐरे के साथ इस्तेमाल करना सीधे तौर पर समर्थित नहीं है। std::make_shared<T[]> से ऐरे बनाना संभव है, लेकिन उनसे सीधे शेयर्ड पॉइंटर बनाने पर अनडिफाइंड बिहेवियर हो सकता है, क्योंकि अकेले ऑब्जेक्ट और ऐरे की मेमोरी मैनेजमेंट में फर्क होता है। इसके बजाय ऐरे को शेयर्ड पॉइंटर के साथ ठीक से मैनेज करने के लिए std::vector या कस्टम डिलीशन फंक्शन इस्तेमाल करने पर विचार कीजिए। C++17 में ऐरे आवंटन और शेयर्ड पॉइंटर के साथ काम करते समय हमेशा अपने कंपाइलर और स्टैंडर्ड लाइब्रेरी के कार्यान्वयन से संगतता सुनिश्चित कीजिए।

std::make_shared() के फायदे

std::make_unique() की तरह std::make_shared() भी बेहतर मेमोरी दक्षता, एक्सेप्शन से सुरक्षा और पढ़ने में आसानी जैसे फायदे देता है। यह कंट्रोल ब्लॉक और मैनेज किए गए ऑब्जेक्ट के लिए मेमोरी आवंटन को एक ही काम में जोड़ देता है, जिससे दक्षता बढ़ती है और मेमोरी लीक का खतरा घटता है। इसके अलावा, टेम्पलेट आर्गुमेंट के अपने आप तय होने से कोड सरल हो जाता है और पढ़ने में आसान बनता है। C++ में std::shared_ptr ऑब्जेक्ट के साथ काम करते समय std::make_shared() इस्तेमाल करने से कोड ज़्यादा साफ, सुरक्षित और कुशल बनता है।

उपयोग की सलाह

आम तौर पर स्मार्ट पॉइंटर ही इस्तेमाल कीजिए: अकेले मालिकाने के लिए std::unique_ptr और साझा मालिकाने के लिए std::shared_ptr। रॉ पॉइंटर सिर्फ ऐसे रेफरेंस के लिए रखिए जो मालिक नहीं हैं, या जब पुराने कोड के साथ काम करना हो। ज़्यादातर मामलों में अकेले मालिकाने के लिए std::unique_ptr काफी होता है, क्योंकि यह रेफरेंस काउंटिंग के अतिरिक्त बोझ के बिना हल्का मेमोरी मैनेजमेंट देता है। std::shared_ptr का इस्तेमाल कम ही कीजिए, क्योंकि जब तक सच में साझा मालिकाना ज़रूरी न हो, यह अतिरिक्त बोझ और जटिलता लेकर आता है।

निर्देश

यह अभ्यास आपको ट्रॉय की दुनिया में ले जाता है। वहाँ के लोगों का जीवन आश्चर्य और जादू से भरा है। ट्रॉय के कई मनुष्यों के पास शक्तियाँ होती हैं, जिनका इस्तेमाल वे अपने रोज़मर्रा के जीवन में बार-बार करते हैं। इन शक्तियों से दुनिया को नया रूप दिया जाता है, या ट्रॉय के जीव-जंतुओं और दूसरे लोगों को प्रभावित किया जाता है। जादू अनोखे आर्टिफैक्ट के रूप में भी प्रकट होता है, जिन्हें साहसी लोग, कारीगर और ऋषि बहुत ढूँढते हैं।

इस अभ्यास में आप कोड लिखकर ट्रॉय के मनुष्यों, उनके पास मौजूद आर्टिफैक्ट और शक्तियों की आपसी क्रिया का मॉडल बनाएँगे।

आपके सामने छह काम हैं। पहला काम एक मनुष्य बनाने से जुड़ा है, और बाकी पाँच शक्तियों और आर्टिफैक्ट को संभालने के बारे में हैं।

1. मनुष्यों को ट्रॉय की दुनिया में लाइए

ट्रॉय के आपके मॉडल में मनुष्य सबसे अहम हैं। आपके मॉडल वाले मनुष्य के पास एक अनोखा आर्टिफैक्ट हो सकना चाहिए। उसमें एक शक्ति प्रकट करने की क्षमता भी होनी चाहिए। ये शक्तियाँ दूसरे मनुष्यों को प्रभावित कर सकती हैं, इसलिए आपको यह भी मॉडल करना है कि कोई मनुष्य किसी और की शक्ति के प्रभाव में है या नहीं।

आपको artifact और power स्ट्रक्चर के बुनियादी कार्यान्वयन दिए गए हैं। एक human स्ट्रक्चर (या क्लास) बनाइए जिसमें possession नाम का एक artifact मेंबर वेरिएबल हो, जो एक स्मार्ट पॉइंटर हो। किसी भी समय एक आर्टिफैक्ट सिर्फ एक ही मनुष्य के पास हो सकता है।

एक human में दो और मेंबर वेरिएबल होने चाहिए। एक में उसका own_power रहता है और दूसरा वह शक्ति है जिससे वह influenced_by है। own_power और influenced_by दोनों powers की ओर इशारा करने वाले स्मार्ट पॉइंटर हैं। हर power किसी एक मनुष्य के पास हो सकती है, लेकिन साथ ही दूसरे मनुष्यों को भी प्रभावित कर सकती है।

डिफॉल्ट रूप से मनुष्य बिना किसी आर्टिफैक्ट के जन्म लेते हैं, न उनके पास कोई शक्ति होती है और न ही वे किसी के प्रभाव में होते हैं।

human mindy_mccready{};
mindy_mccready.possession;
// => nullptr
mindy_mccready.own_power;
// => nullptr
mindy_mccready.influenced_by;
// => nullptr

2. ट्रॉय में आर्टिफैक्ट लाइए

अगर मॉडल के हिस्से आपस में क्रिया न करें, तो वह उबाऊ लगेगा। आप अनोखे आर्टिफैक्ट बनाकर कुछ चुने हुए मनुष्यों को देना चाहते हैं।

give_new_artifact फंक्शन बनाइए, जो कुछ भी लौटाता नहीं, बल्कि एक human और एक string का रेफरेंस लेता है। इस string से यह एक नया artifact ऑब्जेक्ट बनाए और उसी के अनुसार human का possession पॉइंटर सेट करे। फंक्शन को कुछ भी नहीं लौटाना चाहिए।

human erik_magnus_lehnsherr{};
give_new_artifact(erik_magnus_lehnsherr, "Mind shielding helmet");

erik_magnus_lehnsherr.possession->name;
// "Mind shielding helmet"

3. चीज़ों को अदला-बदली के लायक बनाइए

ट्रॉय की दुनिया में सब कुछ आपसी क्रिया पर ही टिका है। आप चाहते हैं कि लोग अपनी चीज़ों की अदला-बदली करके लेन-देन करें।

exchange_artifacts नाम का फंक्शन लिखिए, जो कुछ नहीं लौटाता बल्कि दो आर्टिफैक्ट स्मार्ट पॉइंटर लेकर चीज़ों की अदला-बदली करता है। याद रखिए, आप unique_ptr की कॉपी नहीं बना सकते। यह फंक्शन के पैरामीटर में इस्तेमाल पर भी लागू होता है। इसके बजाय unique_ptr का रेफरेंस इस्तेमाल कीजिए।

human uchiha{};
give_new_artifact(uchiha, "konoha headband");
human uzumaki{};
give_new_artifact(uzumaki, "forehead protector");

exchange_artifacts(uchiha.possession, uzumaki.possession);

uchiha.possession->name;
// "forehead protector"
uzumaki.possession->name;
// "konoha headband"

4. लोगों को शक्ति दीजिए

ट्रॉय की सबसे रोमांचक बात ये खास शक्तियाँ हैं, जो लोगों के पास हो सकती हैं। कुछ लोग अपने विचारों से लोहा पिघला सकते हैं, तो कुछ रात के समय हर घाव को तुरंत भर सकते हैं।

manifest_power फंक्शन बनाइए, जो कुछ भी लौटाता नहीं, बल्कि एक human और एक string का रेफरेंस लेता है। इस string से यह एक नया power ऑब्जेक्ट बनाए और उसी के अनुसार human का own_power पॉइंटर सेट करे। फंक्शन को कुछ भी नहीं लौटाना चाहिए।

human eleven {};
manifest_power(eleven, "psychokinesis");

eleven.own_power->effect;
// "psychokinesis"

5. शक्ति का इस्तेमाल कीजिए

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

एक void फंक्शन use_power लिखिए, जो दो मनुष्यों के रेफरेंस लेता है। पहला मनुष्य शक्ति इस्तेमाल करने वाला है, और दूसरा वह मनुष्य है जिस पर यह शक्ति डाली जाती है। लक्ष्य का influenced_by पॉइंटर शक्ति इस्तेमाल करने वाले की शक्ति की ओर इशारा करना चाहिए।

आसानी के लिए, मनुष्य पर एक समय में सिर्फ एक ही शक्ति का प्रभाव हो सकता है। अगर शक्ति इस्तेमाल करने वाला अब मौजूद न भी हो, तब भी यह शक्ति बनी रहती है।

human pamela_isley{};
manifest_power(pamela_isley, "control pheromones");

human count_vertigo{};
use_power(pamela_isley, count_vertigo);
count_vertigo.influenced_by->effect;
// "control pheromones"

6. शक्ति की तीव्रता पर नज़र रखिए

कुछ शक्तियाँ, जब कई मनुष्यों पर डाली जाती हैं, तो अपना असर खो देती हैं या आपके सिमुलेशन में कुछ खास प्रभाव पैदा करती हैं। आप यह गिनना चाहते हैं कि हर शक्ति से कितने लोग जुड़े हैं।

power_intensity फंक्शन बनाइए, जो एक मनुष्य लेता है और उसकी शक्ति की तीव्रता को int के रूप में लौटाता है। अगर उस व्यक्ति के पास कोई शक्ति नहीं है, तो रिटर्न वैल्यू 0 होनी चाहिए। वरना तीव्रता में शक्ति इस्तेमाल करने वाला और फिलहाल प्रभावित सभी लोग शामिल होने चाहिए।

human jean_grey{};
manifest_power(jean_grey, "uplifting personality");

human scott{};
human logan{};
human ororo{};

use_power(jean_grey, ororo);
use_power(jean_grey, logan);
use_power(jean_grey, scott);

power_intensity(jean_grey);
// 4
GitHub के ज़रिए संपादित करें यह लिंक एक नई विंडो या टैब में खुलता है
C++ Exercism

ट्रॉय की शक्ति शुरू करने के लिए तैयार हैं?

Exercism पर साइन अप कीजिए और C++ को 19 कॉन्सेप्ट100 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।