C++ में Move-सेमैंटिक्स: यह क्या है और शुरुआती के लिए क्यों ज़रूरी है

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

स्मार्ट शब्द "Move सेमैंटिक्स" के पीछे क्या छिपा है?

\n\n

कल्पना करें कि आप एक नए अपार्टमेंट में शिफ्ट हो रहे हैं। आपके पास एक बहुत बड़ा, भारी सोफा है। क्या तेज़ होगा: इसे पाँच मंज़िलों की सीढ़ियों पर खुद ढोना या बस चाबियाँ मूवर्स को दे देना और कहना: "दोस्तों, सोफा आपका है, इसके साथ जो चाहे करें, मुझे इसकी अब ज़रूरत नहीं है"? दूसरा विकल्प ही C++ में move-सेमैंटिक्स है।

\n\n

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

\n\n

Move-सेमैंटिक्स (स्थानांतरण सेमैंटिक्स) एक ऐसा तंत्र है जो महँगी कॉपी किए बिना एक ऑब्जेक्ट से दूसरे ऑब्जेक्ट में संसाधनों (मेमोरी, फ़ाइल डिस्क्रिप्टर, सॉकेट) को स्थानांतरित करने की अनुमति देता है। स्थानांतरण के बाद, मूल ऑब्जेक्ट "खाली" लेकिन सही स्थिति में रहता है, और इसे सुरक्षित रूप से नष्ट किया जा सकता है या इसे एक नया मान दिया जा सकता है।

\n\n

इस लेख में, हम rvalue-संदर्भों, std::move फ़ंक्शन, स्थानांतरण कंस्ट्रक्टर और असाइनमेंट ऑपरेटरों को सरल शब्दों में और कोड उदाहरणों के साथ समझेंगे।

\n\n

Move-सेमैंटिक्स के बिना कोड धीमा क्यों चलता है?

\n\n

आइए एक क्लासिक उदाहरण देखें जो 2011 से पहले सभी C++ प्रोग्रामरों को परेशान करता था:

\n\n
#include <iostream>\n#include <vector>\n#include <string>\n\nstd::vector<std::string> createBigVector() {\n    std::vector<std::string> vec(1000000, "Hello");\n    return vec;  // भयानक! दस लाख स्ट्रिंग्स की कॉपी!\n}\n\nint main() {\n    std::vector<std::string> data = createBigVector();\n    std::cout << "Size: " << data.size() << std::endl;\n    return 0;\n}
\n\n

यहाँ क्या हो रहा है? फ़ंक्शन createBigVector एक वेक्टर बनाता है, उसे डेटा से भरता है और लौटाता है। कंपाइलर (बिना ऑप्टिमाइज़ेशन के) निम्नलिखित करता है:

\n
    \n
  1. फ़ंक्शन के अंदर वेक्टर बनाता है।
  2. \n
  3. पूरे वेक्टर को लौटाए गए मान में कॉपी करता है।
  4. \n
  5. मूल वेक्टर को नष्ट करता है।
  6. \n
  7. main में, इस मान को वेरिएबल data में कॉपी करता है।
  8. \n
\n\n

परिणाम: दस लाख स्ट्रिंग्स की दो पूर्ण प्रतियाँ। यह सिर्फ धीमा नहीं है - यह प्रदर्शन के लिए एक आपदा है।

\n\n

Rvalue और Lvalue: C++ की दो दुनियाएँ

\n\n

Move-सेमैंटिक्स को समझने के लिए, दो मूलभूत अवधारणाओं को समझना होगा: lvalue और rvalue।

\n\n
    \n
  • Lvalue (left value) — वह ऑब्जेक्ट जिसका मेमोरी में एक पता और एक नाम होता है। आप इसका पता ले सकते हैं (&obj)। उदाहरण: वेरिएबल int x = 5; — x एक lvalue है।
  • \n
  • Rvalue (right value) — एक अस्थायी मान जिसका कोई नाम नहीं होता और वह असाइनमेंट ऑपरेटर के बाईं ओर नहीं आ सकता। उदाहरण: 5, x + 3, फ़ंक्शन का परिणाम getTemp()। आप &(x + 3) नहीं लिख सकते।
  • \n
\n\n

पहले, rvalue-संदर्भ (जिसे && से दर्शाया जाता है) मौजूद नहीं था। कंपाइलर एक अस्थायी ऑब्जेक्ट देखता था और कहता था: "हाँ, यह एक rvalue है, मैं इसके साथ केवल एक ही काम कर सकता हूँ - इसे कॉपी करना या नष्ट करना।" Move-सेमैंटिक्स ने कंपाइलर को तीसरा विकल्प दिया: rvalue से संसाधनों को चुराना, क्योंकि यह वैसे भी जल्द ही नष्ट होने वाला है।

\n\n

std::move और rvalue-संदर्भ कैसे काम करते हैं?

\n\n

std::move फ़ंक्शन केवल एक टाइप कास्ट है। यह वास्तव में डेटा को स्थानांतरित नहीं करता, बल्कि केवल lvalue को rvalue में बदल देता है, जिससे कंपाइलर को ऑब्जेक्ट को "लूटने" की अनुमति मिलती है।

\n\n

एक सरल क्लास पर विचार करें जो डायनामिक मेमोरी का प्रबंधन करती है:

\n\n
#include <iostream>\n#include <cstring>\n\nclass MyString {\nprivate:\n    cha                

ब्लॉग

पुस्तक अनुशंसाएँ