C ++ nullptr कार्यान्वयन कैसे काम करता है?


13

मैं यह जानने के लिए उत्सुक हूं कि कैसे nullptrकाम करता है। मानक N4659 और N4849 कहते हैं:

  1. इसे टाइप करना होगा std::nullptr_t;
  2. आप इसका पता नहीं लगा सकते हैं;
  3. इसे सीधे एक पॉइंटर और पॉइंटर को सदस्य में बदला जा सकता है;
  4. sizeof(std::nullptr_t) == sizeof(void*);
  5. इसका रूपांतरण boolहै false;
  6. इसके मूल्य को अभिन्न प्रकार से अभिन्न रूप में परिवर्तित किया जा सकता है (void*)0, लेकिन पीछे की ओर नहीं;

तो यह मूल रूप से एक ही अर्थ के साथ एक स्थिर है (void*)0, लेकिन इसका एक अलग प्रकार है। मैंने std::nullptr_tअपने डिवाइस पर कार्यान्वयन पाया है और यह इस प्रकार है।

#ifdef _LIBCPP_HAS_NO_NULLPTR

_LIBCPP_BEGIN_NAMESPACE_STD

struct _LIBCPP_TEMPLATE_VIS nullptr_t
{
    void* __lx;

    struct __nat {int __for_bool_;};

    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t() : __lx(0) {}
    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t(int __nat::*) : __lx(0) {}

    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR operator int __nat::*() const {return 0;}

    template <class _Tp>
        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
        operator _Tp* () const {return 0;}

    template <class _Tp, class _Up>
        _LIBCPP_INLINE_VISIBILITY
        operator _Tp _Up::* () const {return 0;}

    friend _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool operator==(nullptr_t, nullptr_t) {return true;}
    friend _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool operator!=(nullptr_t, nullptr_t) {return false;}
};

inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t __get_nullptr_t() {return nullptr_t(0);}

#define nullptr _VSTD::__get_nullptr_t()

_LIBCPP_END_NAMESPACE_STD

#else  // _LIBCPP_HAS_NO_NULLPTR

namespace std
{
    typedef decltype(nullptr) nullptr_t;
}

#endif  // _LIBCPP_HAS_NO_NULLPTR

मैं पहले भाग में अधिक दिलचस्पी ले रहा हूं। यह अंक 1-5 को संतुष्ट करता है, लेकिन मुझे पता नहीं है कि इसका उपवर्ग __nat और इससे जुड़ी हर चीज क्यों है। मैं यह भी जानना चाहूंगा कि यह अभिन्न रूपांतरणों पर विफल क्यों है।

struct nullptr_t2{
    void* __lx;
    struct __nat {int __for_bool_;};
     constexpr nullptr_t2() : __lx(0) {}
     constexpr nullptr_t2(int __nat::*) : __lx(0) {}
     constexpr operator int __nat::*() const {return 0;}
    template <class _Tp>
         constexpr
        operator _Tp* () const {return 0;}
    template <class _Tp, class _Up>
        operator _Tp _Up::* () const {return 0;}
    friend  constexpr bool operator==(nullptr_t2, nullptr_t2) {return true;}
    friend  constexpr bool operator!=(nullptr_t2, nullptr_t2) {return false;}
};
inline constexpr nullptr_t2 __get_nullptr_t2() {return nullptr_t2(0);}
#define nullptr2 __get_nullptr_t2()

int main(){
    long l  = reinterpret_cast<long>(nullptr);
    long l2 = reinterpret_cast<long>(nullptr2); // error: invalid type conversion
    bool b  = nullptr; // warning: implicit conversion
                       // edditor error: a value of type "std::nullptr_t" cannot be used to initialize an entity of type "bool"
    bool b2 = nullptr2;
    if (nullptr){}; // warning: implicit conversion
    if (nullptr2){};
};

2
nullptr_tएक मौलिक प्रकार है। कैसे intलागू किया जाता है?
एलएफ

9
ध्यान दें #ifdef _LIBCPP_HAS_NO_NULLPTR। ऐसा लगता है कि जब कंपाइलर प्रदान नहीं करता है तो यह एक सर्वोत्तम प्रयास है nullptr
क्रिस

5
@Fullfungo मानक कहते हैं कि nullptr_tएक मौलिक प्रकार है। इसे एक वर्ग प्रकार के रूप में लागू करना एक अनुरूप कार्यान्वयन नहीं करता है। देखें क्रिस की टिप्पणी
एलएफ

1
@LF क्या मानक तकनीकी रूप से यह आवश्यक है कि एक मौलिक प्रकार एक वर्ग प्रकार नहीं है?
एरोरिका

2
@ शेरिका: is_classऔर is_null_pointerदोनों एक ही प्रकार के लिए सच नहीं हो सकते। केवल एक विशिष्ट प्रकार के लिए प्राथमिक प्रकार श्रेणी के कार्य सही हो सकते हैं।
निकोल बोल्स

जवाबों:


20

मैं यह जानने के लिए उत्सुक हूं कि nullptr कैसे काम करता है।

यह संभव तरीके से सबसे सरल तरीके से काम करता है: फिएट द्वारा । यह काम करता है क्योंकि C ++ मानक कहता है कि यह काम करता है, और यह काम करता है जिस तरह से करता है क्योंकि C ++ मानक कहता है कि कार्यान्वयन को उस फैशन में काम करना चाहिए ।

यह पहचानना महत्वपूर्ण है कि C ++ भाषा के नियमों का उपयोग करना असंभव है std::nullptr_t। किसी प्रकार के अशक्त पॉइंटर std::nullptr_tसे पॉइंटर के लिए रूपांतरण उपयोगकर्ता-निर्धारित रूपांतरण नहीं है। इसका मतलब है कि आप एक अशक्त पॉइंटर से एक पॉइंटर तक जा सकते हैं, फिर उपयोगकर्ता द्वारा परिभाषित रूपांतरण के माध्यम से किसी अन्य प्रकार के लिए, सभी एक एकल निहित रूपांतरण अनुक्रम में।

यदि आप nullptr_tएक वर्ग के रूप में लागू करते हैं तो यह संभव नहीं है । रूपांतरण ऑपरेटर उपयोगकर्ता-परिभाषित रूपांतरणों का प्रतिनिधित्व करते हैं, और C ++ के अंतर्निहित रूपांतरण अनुक्रम नियम ऐसे अनुक्रम में एक से अधिक उपयोगकर्ता-परिभाषित रूपांतरण की अनुमति नहीं देते हैं।

इसलिए आपके द्वारा पोस्ट किया गया कोड एक अच्छा सन्निकटन है std::nullptr_t, लेकिन यह उससे अधिक कुछ नहीं है। यह प्रकार का वैध कार्यान्वयन नहीं है। यह संभवत: संकलक के पुराने संस्करण से था (संकलक के लिए बैकवर्ड-अनुकूलता कारणों के लिए छोड़ दिया गया), इससे पहले कि संकलक ने उचित समर्थन प्रदान किया std::nullptr_t। आप इसे इस तथ्य से देख सकते हैं कि यह #defineएस है nullptr, जबकि सी ++ 11 कहता है कि nullptrयह एक कीवर्ड है , मैक्रो नहीं।

C ++ कार्यान्वित नहीं कर सकता std::nullptr_t, जैसे C ++ कार्यान्वित intया नहीं कर सकता void*। केवल कार्यान्वयन उन चीजों को लागू कर सकता है। यह वह है जो इसे "मौलिक प्रकार" बनाता है; यह भाषा का एक हिस्सा है ।


इसका मान अभिन्न प्रकार से अभिन्न प्रकार में परिवर्तित किया जा सकता है (शून्य *) 0, लेकिन पीछे नहीं;

नहीं है कोई अंतर्निहित रूपांतरण अभिन्न प्रकार के लिए एक अशक्त सूचक निरंतर से। 0अभिन्न प्रकार से रूपांतरण होता है, लेकिन ऐसा इसलिए है क्योंकि यह पूर्णांक शून्य है, जो कि ... पूर्णांक है।

nullptr_tएक पूर्णांक प्रकार (के माध्यम से ) में डाला जा सकता है reinterpret_cast, लेकिन यह केवल संकेत और करने के लिए परिवर्तित किया जा सकता है bool



"सी + + भाषा के नियमों का उपयोग करके std :: nullptr_t" को लागू करना असंभव है? क्या इसका मतलब है कि C ++ कंपाइलर पूरी तरह से C ++ में नहीं लिखा जा सकता है (मैं अनुमान नहीं लगा रहा हूं)?
उत्तरवासी

3
@ नोथरनर: मेरा मतलब है कि आप एक प्रकार नहीं लिख सकते हैं जो आवश्यक व्यवहार के बिल्कुल बराबर है std::nullptr_t। जैसे आप एक प्रकार नहीं लिख सकते हैं जो कि आवश्यक व्यवहार के बराबर है int। आप पास हो सकते हैं, लेकिन फिर भी महत्वपूर्ण अंतर होंगे। और मैं is_classउस तरह के विशेषता डिटेक्टरों के बारे में बात नहीं कर रहा हूं जो यह उजागर करते हैं कि आपका प्रकार उपयोगकर्ता-परिभाषित है। मूलभूत प्रकारों के आवश्यक व्यवहार के बारे में ऐसी बातें हैं जिन्हें आप केवल भाषा के नियमों का उपयोग करके कॉपी नहीं कर सकते हैं।
निकोल बोल्स

1
बस एक शब्दांकन विचित्र है। जब आप कहते हैं कि "C ++ लागू नहीं हो सकता है nullptr_t" तो आप मोटे तौर पर बोलते हैं। और यह कहते हुए कि "केवल कार्यान्वयन ही इसे लागू कर सकता है" केवल मामलों को भ्रमित करता है। आपके कहने का मतलब यह है कि nullptr_tइसे C ++ लाइब्रेरी में लागू नहीं किया जा सकता क्योंकि यह बेस लैंग्वेज का हिस्सा है।
स्पेंसर

1
@ स्पेंसर: नहीं, मेरा वही मतलब है जो मैंने कहा था: C ++ भाषा का उपयोग उस प्रकार को लागू करने के लिए नहीं किया जा सकता है जो वह सब कुछ करता है जो करने std::nullptr_tकी आवश्यकता होती है। सी ++ के रूप में भाषा एक प्रकार को लागू नहीं कर सकती है जो वह सब कुछ करती है जो करने intकी आवश्यकता होती है।
निकोल बोल्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.