कांस्टीट्यूशन पर मुझे बेच दो


133

तो वास्तव में ऐसा क्यों है कि इसे हमेशा कब्ज का उपयोग करने की सलाह दी जाती है? यह मुझे लगता है कि सी का उपयोग करके सी ++ में मदद से अधिक दर्द हो सकता है। लेकिन फिर, मैं अजगर दृष्टिकोण से इस पर आ रहा हूं: यदि आप कुछ बदलना नहीं चाहते हैं, तो इसे न बदलें। तो उस ने कहा, यहाँ कुछ सवाल हैं:

  1. ऐसा लगता है कि हर बार जब मैं कॉन्स्ट के रूप में कुछ चिह्नित करता हूं, मुझे एक त्रुटि मिलती है और मुझे कॉन्स्टेबल होने के लिए कुछ अन्य फ़ंक्शन को भी बदलना पड़ता है। इसके बाद मुझे किसी अन्य फ़ंक्शन को कहीं और बदलना होगा । क्या यह कुछ ऐसा है जो सिर्फ अनुभव से आसान हो जाता है?

  2. क्या वास्तव में परेशानी की भरपाई के लिए कास्ट का उपयोग करने के लाभ पर्याप्त हैं? यदि आप किसी वस्तु को बदलने का इरादा नहीं रखते हैं, तो केवल उस कोड को क्यों नहीं लिखते हैं जो इसे नहीं बदलता है?

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


1
8yr पुरानी पूर्वव्यापी, लेकिन .. कैसे अपने कोड 100x (इस लाइव देखा) को गति देने के बारे में?
लॉर्रो

1
यहां मेरे उत्तर की जांच करें (संबंधित प्रश्न, मैं एक ही उत्तर कहूंगा): stackoverflow.com/questions/42310477/… BTW: मैं प्यार करता हूँconst
Gines हिडाल्गो

जवाबों:


158

यह "कांस्ट शुद्धता" पर निश्चित लेख है: https://isocpp.org/wiki/faq/const-correctness

संक्षेप में, कास्ट का उपयोग करना अच्छा अभ्यास है क्योंकि ...

  1. यह आपको गलती से बदल रहे चरों से बचाता है जिनका इरादा बदला नहीं गया है,
  2. यह आपको आकस्मिक परिवर्तनशील कार्य करने से बचाता है, और
  3. कंपाइलर इसे ऑप्टिमाइज़ कर सकता है। उदाहरण के लिए, आप से सुरक्षित हैं

    if( x = y ) // whoops, meant if( x == y )

उसी समय, संकलक अधिक कुशल कोड उत्पन्न कर सकता है क्योंकि यह जानता है कि हर समय चर / फ़ंक्शन की स्थिति क्या होगी। यदि आप तंग C ++ कोड लिख रहे हैं, तो यह अच्छा है।

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


मैंने हमेशा यह माना कि कॉन्स्टेबल वैल्यू को स्वतंत्र रूप से कैश किया जा सकता है और इस तरह कई कंसर्ट प्रॉब्लम से बचा जा सकता है या स्पीड में सुधार हो सकता है। क्या यह सच है?
फिल एच।

3
ज़रूर। constचर इस अर्थ में गति में सुधार कर सकते हैं कि संकलक अधिक इष्टतम कोड उत्पन्न कर सकता है क्योंकि यह चर के पूर्ण इरादे और उपयोग को जानता है। क्या आप अंतर नोटिस करेंगे? ठीक है, यह आपके आवेदन पर बहस योग्य है। जहाँ तक संगामिति का सवाल है, कॉन्स्टेबल-वेरिएबल्स केवल-पढ़े जाते हैं, जिसका मतलब है कि उन वेरिएबल्स पर एक्सक्लूसिव लॉक की जरूरत नहीं है क्योंकि वैल्यू हमेशा एक ही रहेगी।
जॉर्डन पैरा

4
C ++ 11 के रूप में मानक पुस्तकालय भी constथ्रेड-सुरक्षित मतलब है और अपने स्वयं के कोड का इलाज करने के लिए इस तरह से संभव बहु-थ्रेडिंग समस्याओं की जाँच करना आसान बनाता है और आपके एपीआई उपयोगकर्ताओं के लिए एपीआई गारंटी प्रदान करने का एक आसान तरीका है।
पहर

3
मेरे लिए, कांस्ट शुद्धता का एक सबसे बड़ा मूल्य यह है कि आप केवल फ़ंक्शन प्रोटोटाइप को देखकर जानते हैं जब पॉइंटर्स डेटा संदर्भित कर रहे हैं जो फ़ंक्शन द्वारा कभी भी उत्परिवर्तित नहीं होता है (केवल इनपुट)।
cp.engr

1
यह मत भूलो कि तार्किक और शारीरिक स्थिरता है। किसी भी कुल वस्तु को समाहित किया जा सकता है, जिसे उत्परिवर्तित के रूप में चिह्नित किया जा सकता है, हालांकि इसे इस तरह से चिह्नित किया जाता है कि इसमें युक्त वस्तु की तार्किक स्थिरता के साथ कुछ भी नहीं है।
एड्रियन

128

यहां एक सामान्य त्रुटि के साथ कोड का एक टुकड़ा है, जो कि सही शुद्धता आपके विरुद्ध सुरक्षा कर सकता है:

void foo(const int DEFCON)
{
   if (DEFCON = 1)     //< FLAGGED AS COMPILER ERROR! WORLD SAVED!
   {
       fire_missiles();
   }
}

19
तो हम कह रहे हैं कि कास्ट आवश्यक है क्योंकि कुछ खूनी बेवकूफ ने सी में असाइनमेंट ऑपरेटर के रूप में "=" चुना? ;-)
स्टीव जेसप

37
बेशक, अधिकांश आधुनिक संकलक सशर्त में असाइनमेंट के बारे में चेतावनी देते हैं और हम सभी त्रुटियों के झंडे के रूप में ट्रीटमेंट चेतावनियों को चालू करते हैं: ->
जैक बोलिंग

7
उस उदाहरण पर बहुत कठिन मत बनो: यह वही उदाहरण है जो कुछ डेवलपर्स द्वारा प्रचारित किया गया है ताकि हमें यह समझाने के लिए कि यदि (0 == i) का उपयोग किया जाए तो (i == 0)। अंत में, कोड के डौग के पैटर्न का उपयोग "यदि" कथन के बाहर किया जा सकता है। क्या महत्वपूर्ण है यह हास्य के तरीके में से एक के फायदे को दर्शाता है। + 1.
पियरसबल

2
कुछ कंपाइलर (और लिन्ट्स) इस बारे में लंबे समय से चेतावनी दे रहे हैं, और यह इस टाइपो को पकड़ने के लिए बहुत अधिक उपयोगी है: constpad.org/Nnf5JUXV

7
@Roger आप मान लेते हैं कि हम एक ऐसी दुनिया में रहते हैं जहाँ बिल्ड साफ और चेतावनी मुक्त हैं। मेरा अनुभव है कि बहुत सारे कोड चेतावनियाँ शोर में खो जाती हैं। इसके अलावा, बहुत सारे कोड हैं जो यदि अभिव्यक्ति में असाइनमेंट करते हैं और कई तर्क देंगे कि यह एक वैध, "अच्छा" शैली है।
डग टी।

62

ऐसा लगता है कि हर बार जब मैं कॉन्स्ट के रूप में कुछ चिह्नित करता हूं, मुझे एक त्रुटि मिलती है और मुझे कॉन्स्टेबल होने के लिए कुछ अन्य फ़ंक्शन को भी बदलना पड़ता है। इसके बाद मुझे किसी अन्य फ़ंक्शन को कहीं और बदलना होगा। क्या यह कुछ ऐसा है जो सिर्फ अनुभव से आसान हो जाता है?

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


7
इससे मुझे इतने सारे कीड़ों को रोकने में मदद मिली है, जहां मेरे पास एक कॉन्स्टेबल फंक्शन था, नॉन-कॉस्ट फंक्शन को कॉल करने के बारे में क्योंकि मैं भूल गया था कि यह डेटा को नीचे से संशोधित करता है।
मूइंग डक

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

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

4
"यदि आप शुरू से ही कॉन्स्ट-सही डिज़ाइन करते हैं," तो आपको वास्तव में शुरू से ही कॉस्ट-करेक्शन को मजबूर करने की लक्जरी कितनी बार मिलती है ?? हम में से अधिकांश को दैनिक आधार पर कई एपीआई और पुस्तकालयों से निपटना पड़ता है जहां ऐसा नहीं होता है और ऐसा बहुत कम होता है जो आप उन लोगों के साथ कर सकते हैं। इसलिए मैं ओपी भावना से सहमत हूं "ऐसा लगता है कि हर बार जब मैं
कॉन्स्टेबल के

@ArrenDew यह एक सकर्मक तर्क है; यदि मूल लेखकों ने constठीक से उपयोग किया था (अर्थात "प्रारंभ से") तो वास्तव में कोई समस्या नहीं होगी, जो कि वास्तव में बिंदु है!
ऑर्बिट में लाइटनेस दौड़

31

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


1
यह केवल एक प्रकार का सच है। कॉन्स्टैप्ट का उपयोग सुरक्षा के साथ-साथ इंटरफेस के माध्यम से और इसके बाद लागू करने के लिए किया जाता है।
जॉर्डन पैमर

यह है, लेकिन आप इसे अनुशासित कोडिंग प्रथाओं और पोस्टर के माध्यम से लागू कर सकते हैं। इसका वास्तविक लाभ एपीआई में परिलक्षित होता है।
एंटोनियो हेली

2
बिल्कुल सही। "कॉन्स्टेबल वैल्यू = 5" रखना बेहतर है; की तुलना में "int ConstValue = 5;"। +1।
पियरसबल

6
जब आप API को शुरू में लिखते हैं तो कॉन्स्ट-करेक्शन करने का सही समय होता है। अन्यथा जब आप इसे वापस लेते हैं तो आपको कब्ज-विषाक्तता की समस्या हो जाती है (इसीलिए इसे पुराने कोड में जोड़ना नए कोड में करने के लिए पूरी तरह से अलग मामला है)।
डोनाल्ड फेलो

@DonalFellows यह नहीं कह रहा है कि बाद में कास्ट में डाल दिया गया है। यह कह रहा है कि आप बाद में लाभ प्राप्त करते हैं , जब आप पहले से मौजूद
कास्ट

27

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


1
चूंकि C ++ 17 और कॉन्स्टैक्स अच्छाई मैं कंपाइल टाइम यूनिट टेस्ट लिख रहा हूं ... अभी भी पास हो रहा
हूं

22

const एक वादा है जिसे आप डेवलपर के रूप में बना रहे हैं, और संकलक की मदद को लागू करने में सक्षम कर रहे हैं।

कब्ज-सही होने के मेरे कारण:

  • यह आपके फ़ंक्शन के क्लाइंटों को सूचित करता है कि आपका वेरिएबल या ऑब्जेक्ट नहीं बदलेगा
  • कॉन्स्ट रेफरेंस द्वारा तर्कों को स्वीकार करना आपको वैल्यू से गुजरने की सुरक्षा के संदर्भ में पास करने की दक्षता प्रदान करता है।
  • अपने इंटरफेस को कॉन्स्ट सही लिखने से ग्राहक उनका उपयोग कर सकेंगे। यदि आप अपने इंटरफेस को नॉन-कॉस्ट संदर्भों में लेने के लिए लिखते हैं, तो जो ग्राहक कॉन्स्ट का उपयोग कर रहे हैं, उन्हें आपके साथ काम करने के लिए निरंतरता को दूर करना होगा। यह विशेष रूप से कष्टप्रद है अगर आपका इंटरफ़ेस नॉन-कास्ट चार * स्वीकार करता है, और आपके क्लाइंट एसटीडी :: स्ट्रिंग्स का उपयोग कर रहे हैं, क्योंकि आप केवल उनसे एक कॉन्स्टर्ड चार * प्राप्त कर सकते हैं।
  • कास्ट का उपयोग करने से आपको ईमानदार रखने में कंपाइलर का उपयोग किया जाएगा, ताकि आप गलती से ऐसा कुछ न बदलें जो बदलना नहीं चाहिए।

20

मेरा दर्शन यह है कि यदि आप संकलित समय जांच के साथ एक नाइट-पिकी भाषा का उपयोग करने जा रहे हैं तो आप इसका सर्वोत्तम उपयोग कर सकते हैं। constएक संकलक लागू करने का तरीका है जो आपके कहने का अर्थ है ... यह टिप्पणियों या डॉक्स ऑक्सीजन की तुलना में बेहतर है। आप मूल्य का भुगतान कर रहे हैं, मूल्य क्यों नहीं प्राप्त करें?


20

बिना गति के C ++ का प्रोग्रामिंग करना सुरक्षा बेल्ट के बिना ड्राइविंग के समान है।

हर बार जब आप कार में कदम रखते हैं तो सुरक्षा बेल्ट लगाना एक दर्द होता है, और 365 दिनों में से 364 आप सुरक्षित रूप से पहुंचेंगे।

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


18

एम्बेडेड प्रोग्रामिंग के लिए, constवैश्विक डेटा संरचनाओं की घोषणा करते समय विवेकपूर्ण रूप से उपयोग करते हुए, बूट समय पर रैम की नकल किए बिना निरंतर डेटा को ROM या फ्लैश में स्थित होने के कारण बहुत से रैम को बचाया जा सकता है।

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

जब बड़ी परियोजनाओं पर अन्य प्रोग्रामर के साथ काम करते हैं, तो constठीक से उपयोग करने से अन्य प्रोग्रामर को आपको थ्रॉटलिंग से रोकने में मदद मिलती है।


13

constआपको कोड को अलग करने में मदद करता है जो आपकी पीठ के पीछे "चीजें बदलें"। इसलिए, एक कक्षा में, आप उन सभी तरीकों को चिह्नित करेंगे जो ऑब्जेक्ट की स्थिति को बदलते नहीं हैं const। इसका मतलब है कि constउस वर्ग के उदाहरण अब किसी भी गैर- constतरीकों को कॉल करने में सक्षम नहीं होंगे । इस तरह, आपको गलती से कॉलिंग कार्यक्षमता से रोका जा सकता है जो आपकी वस्तु को बदल सकता है।

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

उदाहरण:

#include <iostream>

class HelloWorld {
    bool hw_called;

public:
    HelloWorld() : hw_called(false) {}

    void hw() const {
        std::cout << "Hello, world! (const)\n";
        // hw_called = true;  <-- not allowed
    }

    void hw() {
        std::cout << "Hello, world! (non-const)\n";
        hw_called = true;
    }
};

int
main()
{
    HelloWorld hw;
    HelloWorld* phw1(&hw);
    HelloWorld const* phw2(&hw);

    hw.hw();    // calls non-const version
    phw1->hw(); // calls non-const version
    phw2->hw(); // calls const version
    return 0;
}

13

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

मेरे द्वारा लिखे गए बहुत सारे कोड में, यह वास्तव में इस प्रयास के लायक था क्योंकि हम रचना का बहुत उपयोग करते हैं:

class A { ... }
class B { A m_a; const A& getA() const { return m_a; } };

यदि हमारे पास कांस्ट-शुद्धता नहीं थी, तो आपको अपने आप को आश्वस्त करने के लिए जटिल वस्तुओं को वापस करने के लिए मूल्य का सहारा लेना होगा ताकि कोई भी आपकी पीठ के पीछे वर्ग बी की आंतरिक स्थिति में हेरफेर न कर सके।

संक्षेप में, अपने आप को सड़क के नीचे दर्द से बचाने के लिए कॉन्स्टीट्यूशन एक रक्षात्मक प्रोग्रामिंग तंत्र है।


7

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

C ++ आपको खुद को गलती से कुछ ऐसा करने से बचाने का एक तरीका देता है जिसे आप पहली बार में करने में सक्षम नहीं थे। तकनीकी रूप से आप इसे वैसे भी प्राप्त कर सकते हैं, लेकिन आपको खुद को शूट करने के लिए अतिरिक्त काम करना होगा।


4

C ++ में const के बारे में यहाँ एक अच्छा लेख है । यह एक बहुत सीधे आगे की राय है, लेकिन आशा है कि यह कुछ मदद करता है।


3

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

हाँ, यह समय के साथ आसान हो जाता है।


2

मुझे कॉन्स्टीट्यूशन में कॉन्स्टेबलिटी पसंद है ... हर बार जब मैंने इसे कठोरता से लागू करने की कोशिश की है तो यह अंततः टूट गया है और कोड को बदसूरत बनाने के लिए कॉन्स्टैप कास्ट शुरू हो गया है।

हो सकता है कि यह केवल मेरे द्वारा उपयोग किए जाने वाले डिज़ाइन पैटर्न हो, लेकिन हमेशा ब्रश को चौड़ा करने से कॉन्स्ट हमेशा समाप्त होता है।

उदाहरण के लिए, एक साधारण डेटाबेस इंजन की कल्पना करें ... इसमें स्कीमा ऑब्जेक्ट्स, टेबल, फ़ील्ड्स आदि हैं। एक उपयोगकर्ता के पास एक 'कास्ट टेबल' पॉइंटर हो सकता है जिसका अर्थ है कि उन्हें टेबल स्कीमा को संशोधित करने की अनुमति नहीं है ... लेकिन हेरफेर के बारे में क्या तालिका से संबंधित डेटा? यदि इन्सर्ट () विधि को कॉस्ट के रूप में चिह्नित किया जाता है तो आंतरिक रूप से कॉन्स्टिट-नेस को वास्तव में डेटाबेस में हेरफेर करना पड़ता है। यदि यह कॉन्स्टेड चिह्नित नहीं है, तो यह AddField विधि को कॉल करने से बचाता नहीं है।

हो सकता है कि इसका उत्तर यह है कि कास्ट-नेस आवश्यकताओं के आधार पर कक्षा को विभाजित किया जाए, लेकिन इससे डिजाइन को अधिक जटिल हो जाता है, जितना मैं इसे लाता है।


मुझे लगता है कि आपका उदाहरण कब्ज को खत्म करने का एक मामला है, लेकिन उत्परिवर्तित संशोधक के बारे में मत भूलना, जिसे कॉस्ट-नेस को हटाने के लिए उदाहरण चर पर लागू किया जा सकता है।
जोबा

2
जब तक कोई सम्मिलन () फ़ंक्शन को तब तक कास्ट नहीं किया जाएगा जब तक कि उसका नाम न हो? चीजों को जोड़ना आमतौर पर उस चीज़ को संशोधित करता है जिसे आपने इसे जोड़ा था, जिसका अर्थ है कि यह स्थिर नहीं है। क्या आप वास्तव में चाहते थे एक TableWithConstSchema था।
ग्रेग रोजर्स

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

1

आप संकलक के साथ संकलक संकेत दे सकते हैं .... निम्न कोड के अनुसार

#include <string>

void f(const std::string& s)
{

}
void x( std::string& x)
{
}
void main()
{
    f("blah");
    x("blah");   // won't compile...
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.