ऐसा लगता है कि यह एक डुप्लिकेट होगा, लेकिन शायद यह इतना स्पष्ट है कि इसे नहीं पूछा गया है ...

क्या यह जाँचने का सही तरीका है कि C++ क्लास में एक वेरिएबल (पॉइंटर नहीं) को इनिशियलाइज़ किया गया है या नहीं?

class MyClass
{
    void SomeMethod();

    char mCharacter;
    double mDecimal;
};

void MyClass::SomeMethod()
{
    if ( mCharacter )
    {
        // do something with mCharacter.
    }

    if ( ! mDecimal )
    {
        // define mDecimal.
    }
}
62
user542687 26 जुलाई 2011, 00:36
2
"परिभाषित किया गया है" से आपका क्या मतलब है? क्या आपका मतलब है "एक मूल्य है" "प्रारंभिक" के रूप में?
 – 
NirMH
26 जुलाई 2011, 00:38
सभी चरों का हमेशा एक मान होता है (वे परिभाषित हैं)। आम तौर पर कंपाइलर कुछ मानक मान के लिए चर प्रारंभ करते हैं, लेकिन मुझे यकीन नहीं है कि यह सी ++ की परिभाषा का हिस्सा है, जहां तक ​​​​मुझे पता है कि यह नहीं है। सभी चरों का उपयोग करने से पहले उन्हें प्रारंभ करना एक अच्छा अभ्यास है, ताकि उनके पास कभी भी कुछ यादृच्छिक या कार्यान्वयन-निर्भर मूल्य न हो। फिर आप उनका उपयोग करने से पहले किसी भी समय उनके वर्तमान मूल्य की जांच कर सकते हैं।
 – 
Giorgio
26 जुलाई 2011, 00:43
1
@ जय, आपको सी ++ का उपयोग करने वाले शब्दों से मेल खाने के लिए वास्तव में अपने प्रश्न को दोबारा लिखने की ज़रूरत है। C++ नियमों के अनुसार, आपके उदाहरण में mCharacter हमेशा MyClass में परिभाषित होता है। 'चार mCharacter' वहां दिखाई देने का मतलब है कि इसे परिभाषित किया गया है। अब आपको यह सोचने की ज़रूरत है कि "एम कैरेक्टर परिभाषित है" द्वारा आपको वास्तव में क्या चाहिए। क्या आपका मतलब है, "असाइन किया गया?"। सी ++ वास्तव में इसकी जांच नहीं कर सकता है। "क्या मूल्य आरंभीकरण मूल्य से भिन्न है"? हो सकता है, लेकिन फिर, आपके उदाहरण में कोई प्रारंभिक मान नहीं है, इसलिए आप इसकी भी जांच नहीं कर सकते, जब तक कि आप प्रारंभकर्ता और कन्स्ट्रक्टर नहीं जोड़ते। इस रूप में, प्रश्न को फिर से लिखा जाना चाहिए
 – 
Andrei
26 जुलाई 2011, 00:44
1
आप पॉइंटर्स को अलग क्यों करते हैं? सूचक चर एक सूचक प्रकार के साथ केवल चर हैं।
 – 
Giorgio
26 जुलाई 2011, 00:46
2
सी ++ 17 संभावना के आगमन के साथ सही उत्तर बेहतर नहीं होगा?
 – 
Rodrigo Gurgel
21 फरवरी 2018, 17:43

13 जवाब

सबसे बढ़िया उत्तर

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

42
Alexander Gessler 26 जुलाई 2011, 00:40
4
दुर्भाग्य से, यह उत्तर सही नहीं है। यदि आप C++-11 पर विचार करते हैं, तो प्रहरी मूल्य का उपयोग किए बिना कक्षा के सदस्यों के लिए कार्यान्वयन है, नीचे मेरा उत्तर देखें।
 – 
Twonky
4 जून 2017, 00:44
यह अभी भी सही है। स्मार्ट पॉइंटर या std::optional का उपयोग करना एक bool ("सिग्नल") के समान है जो यह चिन्हित करता है कि वेरिएबल को इनिशियलाइज़ किया गया है या नहीं।
 – 
user202729
2 अक्टूबर 2020, 10:47

वेरिएबल जो परिभाषित नहीं है, संकलन त्रुटि का कारण बनेगा।

आप जो पूछ रहे हैं वह यह जांचने के बारे में है कि क्या यह आरंभिक है। लेकिन इनिशियलाइज़ेशन सिर्फ एक वैल्यू है, जिसे आपको कंस्ट्रक्टर में चुनना और असाइन करना चाहिए।

उदाहरण के लिए:

class MyClass
{
    MyClass() : mCharacter('0'), mDecimal(-1.0){};
    void SomeMethod();

    char mCharacter;
    double mDecimal;
};

void MyClass::SomeMethod()
{
    if ( mCharacter != '0')
    {
        // touched after the constructor
        // do something with mCharacter.
    }

    if ( mDecimal != -1.0 )
    {
        // touched after the constructor
        // define mDecimal.
    }
}

आपको एक डिफ़ॉल्ट मान के लिए प्रारंभ करना चाहिए जिसका अर्थ निश्चित रूप से आपके तर्क के संदर्भ में कुछ होगा।

24
littleadv 26 जुलाई 2011, 00:39
इस उत्तर में जोड़कर, आप सी-टोर में एक अमान्य मान सेट कर सकते हैं और जांच सकते हैं कि यह आपकी विधि के दौरान अभी भी अमान्य है या नहीं। या बूलियन का उपयोग करके ध्वजांकित करने के लिए मान को प्रारंभिक अमान्य से बदल दिया गया था
 – 
NirMH
26 जुलाई 2011, 00:40
1
मैं लगभग हमेशा कहूंगा कि यदि आपके पास निर्माण पर एक वैध वस्तु बनाने की जानकारी नहीं है, तो उस निर्माता को एक वैध वस्तु बनाने के लिए पर्याप्त जानकारी के साथ एक निर्माता के पक्ष में हटा दिया जाना चाहिए।
 – 
Mark B
26 जुलाई 2011, 00:58
ठीक यही @alexander-gessler का अपने सिग्नल/सेंटिनल मान से मतलब था
 – 
fiorentinoing
13 अप्रैल 2018, 13:49

आपके अनुप्रयोगों के आधार पर (और विशेष रूप से यदि आप पहले से ही बूस्ट का उपयोग कर रहे हैं), तो हो सकता है कि आप boost::optional.

(अद्यतन: C++17 के अनुसार, वैकल्पिक अब मानक पुस्तकालय का हिस्सा है, जैसा कि std::optional)

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

class MyClass
{
    void SomeMethod();

    optional<char> mCharacter;
    optional<double> mDecimal;
};

void MyClass::SomeMethod()
{
    if ( mCharacter )
    {
        // do something with *mCharacter.
        // (note you must use the dereference operator)
    }

    if ( ! mDecimal )
    {
        // call mDecimal.reset(expression)
        // (this is how you assign an optional)
    }
}

अधिक उदाहरण बूस्ट दस्तावेज़ों में हैं< /ए>.

16
HostileFork says dont trust SE 13 नवम्बर 2018, 22:08

C++-11 या बूस्ट लिब के साथ आप स्मार्ट पॉइंटर्स का उपयोग करके वेरिएबल को स्टोर करने पर विचार कर सकते हैं। इस एमवीई पर विचार करें जहां toString() व्यवहार bar के आरंभिक होने या न होने पर निर्भर करता है:

#include <memory>
#include <sstream>

class Foo {

private:
    std::shared_ptr<int> bar;

public:
    Foo() {}
    void setBar(int bar) {
        this->bar = std::make_shared<int>(bar);
    }
    std::string toString() const {
        std::ostringstream ss;
        if (bar)           // bar was set
            ss << *bar;
        else               // bar was never set
            ss << "unset";
        return ss.str();
    }
};

इस कोड का उपयोग करना

Foo f;
std::cout << f.toString() << std::endl;
f.setBar(42);
std::cout << f.toString() << std::endl;

उत्पादन करता है

unset
42
4
Twonky 8 मार्च 2020, 13:56
क्या यह एक गैर-सूचक चर के लिए काम करेगा उदा। Foo f; if (f) ... -- यह मेरे लिए काम नहीं कर रहा है, लेकिन शायद कोई और तरीका है?
 – 
ekkis
17 नवम्बर 2019, 03:13
2
नहीं, स्मार्ट पॉइंटर्स समाधान केवल पॉइंटर वेरिएबल्स के लिए काम करता है। यदि आपको अपने चर को स्टैक पर रखना है, तो मेरा सुझाव है कि std::optional का उपयोग करके एल्मर के समाधान का उपयोग करें।
 – 
Twonky
18 नवम्बर 2019, 15:42
एमवीई क्या है? न्यूनतम व्यवहार्य उदाहरण? न्यूनतम व्यवहार्य प्रयोग?
 – 
Joe Flack
20 नवम्बर 2019, 22:19
मुझे लगता है कि यह सही नहीं है क्योंकि स्मार्ट पॉइंटर्स का आकार आपके चर से बड़ा है। यह आपके चर के लिए ध्वज को परिभाषित करने के समान है और सेटर फ़ंक्शन में सत्य पर सेट है।
 – 
Amir
8 मार्च 2020, 02:10
@ आमिर: आप यह इंगित करने के साथ सही हैं कि स्मार्ट पॉइंटर्स का उपयोग एक बड़ी मेमोरी पदचिह्न का तात्पर्य है। हालाँकि, प्रश्न ने यह संकेत नहीं दिया कि स्मृति उपयोग मायने रखेगा। उन्नत प्रोग्रामिंग तकनीकों के कई प्रयासों का उद्देश्य चीजों को स्वचालित रूप से करना है, इसलिए कुछ करने को भूलने का कोई मौका नहीं है। स्मार्ट पॉइंटर्स का उपयोग करना, या std::optional जैसा कि एल्मर ने सुझाव दिया था, यह दावा करता है कि आप हमेशा जांच सकते हैं कि चर ने संकेत दिया है या नहीं। आपके द्वारा इंगित ध्वज का उपयोग करके भूलने का कोई मौका नहीं है। प्लस: चर को सीधे एक्सेस करने के बजाय सेटर्स के उपयोग को लागू करने की आवश्यकता नहीं है।
 – 
Twonky
8 मार्च 2020, 14:01

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

class MyVeryCoolInteger
{
public:
    MyVeryCoolInteger() : m_initialized(false) {}

    MyVeryCoolInteger& operator=(const int integer)
    {
        m_initialized = true;
        m_int = integer;
        return *this;
    }

    int value()
    {
        return m_int;
    }

    bool isInitialized()
    {
        return m_initialized;
    }

private:
    int m_int;
    bool m_initialized;
};
3
Chris Eberle 26 जुलाई 2011, 00:49
1
आपका बहुत अच्छा पूर्णांक एक टेम्पलेट के रूप में अधिक सारगर्भित रूप से मौजूद है, और इसे boost::optional कहा जाता है। (मेरा उत्तर देखें।) यदि आपके पास ऐसी स्थिति है तो इसका उपयोग करने में कुछ भी गलत नहीं है। हालांकि निश्चित रूप से यदि आपके पास लाखों पूर्णांक हैं, तो यह "कोई मूल्य नहीं" इंगित करने के लिए एक जादू मूल्य चुनने के लिए अच्छी तरह से भुगतान कर सकता है।
 – 
HostileFork says dont trust SE
26 जुलाई 2011, 00:57
अरे कोई शक नहीं। लेकिन जैसा कि बताया गया है, मैंने सोचा कि मैं एक वैकल्पिक उत्तर दूंगा।
 – 
Chris Eberle
26 जुलाई 2011, 06:54

यह जांचने का कोई उचित तरीका नहीं है कि कोई मान प्रारंभ किया गया है या नहीं।

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

2
Jerry Coffin 26 जुलाई 2011, 01:13

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

#include <limits>

class MyClass
{
    void SomeMethod();

    char mCharacter;
    bool isCharacterInitialized;
    double mDecimal;

    MyClass()
    : isCharacterInitialized(false)
    , mDecimal( std::numeric_limits<double>::quiet_NaN() )
    {}


};


void MyClass::SomeMethod()
{
    if ( isCharacterInitialized == false )
    {
        // do something with mCharacter.
    }

    if ( mDecimal != mDecimal ) // if true, mDecimal == NaN
    {
        // define mDecimal.
    }
}
1
Praetorian 26 जुलाई 2011, 00:44

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

यदि आप अपनी कक्षा के गैर-स्थिर डेटा सदस्यों को शून्य-प्रारंभ करना चाहते हैं, तो प्रारंभिक सूची और कक्षा-निर्माता बनाना सबसे अच्छा होगा। उदाहरण के लिए:

class MyClass
{
    void SomeMethod();

    char mCharacter;
    double mDecimal;

    public:
        MyClass();
};

MyClass::MyClass(): mCharacter(0), mDecimal(0) {}

मूल्य से ऊपर के कंस्ट्रक्टर में इनिशियलाइज़ेशन सूची आपके डेटा-सदस्यों को शून्य पर आरंभ करती है। अब आप ठीक से मान सकते हैं कि mCharacter और mDecimal के लिए कोई भी गैर-शून्य मान विशेष रूप से आपके द्वारा आपके कोड में कहीं और निर्धारित किया गया होगा, और इसमें गैर-शून्य मान शामिल हैं जिन पर आप ठीक से कार्य कर सकते हैं।

1
Jason 26 जुलाई 2011, 01:09
सदस्य चर को डिफ़ॉल्ट या यादृच्छिक मानों के लिए प्रारंभ नहीं किया जाता है जब ऑब्जेक्ट को तत्काल किया जाता है जब तक यह स्पष्ट रूप से c-tor में नहीं किया जाता है। कई डिबग रनटाइम स्मृति को एक विशिष्ट मान पर प्रारंभ करेंगे जब इसे आवंटित किया जाता है (नया), अन्यथा यह यूबी है और मान तत्कालता से पहले स्मृति में जो कुछ भी होगा।
 – 
Captain Obvlious
26 जुलाई 2011, 00:52
MyClass के लिए डिफॉल्ट कंस्ट्रक्टर, चूंकि यह ओपी के मूल संस्करण में किसी भी वेरिएबल को वैल्यू-इनिशियलाइज़ नहीं करता है, डेटा सदस्यों के लिए रैंडम वैल्यू बनाएगा ... एक रैंडम वैल्यू (यानी, मेमोरी में पहले से मौजूद वैल्यू) है POD डेटा-प्रकार के लिए डिफ़ॉल्ट-आरंभीकरण।
 – 
Jason
26 जुलाई 2011, 00:59
"डिफ़ॉल्ट-यादृच्छिक मानों के साथ प्रारंभ" - इस कथन का तात्पर्य है कि डिफ़ॉल्ट रूप से कुछ प्रकार का प्रारंभिक होता है जो चर में यादृच्छिक मान संग्रहीत करता है। सही शब्द बस "अप्रारंभीकृत" है
 – 
Captain Obvlious
26 जुलाई 2011, 01:02
मैं वास्तव में इसके बारे में इस तरह के नाजी की तरह आवाज नहीं करना चाहता था;)
 – 
Captain Obvlious
26 जुलाई 2011, 01:12

सी ++ भाषा में यह जांचने का कोई तरीका नहीं है कि एक चर प्रारंभ किया गया है या नहीं (हालांकि रचनाकारों के साथ वर्ग प्रकार स्वचालित रूप से प्रारंभ हो जाएंगे)।

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

0
Mark B 26 जुलाई 2011, 01:02

उदाहरण के लिए यदि आप वर्णों के बजाय तार का उपयोग करते हैं, तो आप ऐसा कुछ करने में सक्षम हो सकते हैं:

    //a is a string of length 1
    string a;
    //b is the char in which we'll put the char stored in a
    char b;
    bool isInitialized(){
      if(a.length() != NULL){
        b = a[0];
        return true;
      }else return false;
    }
0
Allan Lago 18 नवम्बर 2016, 12:02

आप एक अभिकथन में चर का संदर्भ दे सकते हैं और फिर -fsanitize=address के साथ निर्माण कर सकते हैं:

void foo (int32_t& i) {
    // Assertion will trigger address sanitizer if not initialized:
    assert(static_cast<int64_t>(i) != INT64_MAX);
}

यह प्रोग्राम को स्टैक ट्रेस (अपरिभाषित व्यवहार के विपरीत) के साथ विश्वसनीय रूप से क्रैश करने का कारण बनता है।

0
sffc 1 मई 2018, 02:03

अगर आपको बूस्ट और c++17 पसंद नहीं है, तो google c++ lib Abseil इसे महसूस करने का दूसरा तरीका है। absl::वैकल्पिक बिल्कुल std :: वैकल्पिक की तरह है।

#include <absl/types/optional.h>
class MyClass
{
    void SomeMethod();

    absl::optional<char> mCharacter;
    absl::optional<double> mDecimal;
};

void MyClass::SomeMethod()
{
    if (mCharacter)
    {
        // do something with mCharacter.
    }

    if (!mDecimal)
    {
        // define mDecimal.
    }
}
0
Paul Yu 19 मई 2020, 07:08