C ++ nullptr uygulaması nasıl çalışır?


13

Nasıl nullptrçalıştığını merak ediyorum . N4659 ve N4849 standartları şunları söylüyor:

  1. tipi olmalıdır std::nullptr_t;
  2. adresini alamazsın;
  3. doğrudan bir işaretçiye ve işaretçiye üyeye dönüştürülebilir;
  4. sizeof(std::nullptr_t) == sizeof(void*);
  5. için, dönüşüm boolIS false;
  6. değeri aynı şekilde integral tipe dönüştürülebilir (void*)0, ancak geriye doğru değil;

Yani temelde aynı anlama sahip bir sabittir (void*)0, ancak farklı bir türü vardır. std::nullptr_tCihazımda uygulamasını buldum ve şu şekildedir.

#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

Yine de ilk kısımla daha fazla ilgileniyorum. 1-5 puanları tatmin ediyor gibi görünüyor, ama neden bir alt sınıf __nat ve onunla ilgili her şeye sahip olduğu hakkında hiçbir fikrim yok. Ayrılmaz neden dönüşümlerde başarısız olduğunu da bilmek isterim.

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_ttemel bir tiptir. Nasıl intuygulanır?
LF

9
Not #ifdef _LIBCPP_HAS_NO_NULLPTR. Bu, derleyicinin sağlamadığı zamanlar için en iyi çaba çözümü gibi görünüyor nullptr.
chris

5
@Fullfungo Standart bunun nullptr_ttemel bir tür olduğunu söylüyor . Sınıf türü olarak uygulanması uygun bir uygulama yapmaz. Chris'in yorumuna bakın.
LF

1
@LF Standart teknik olarak temel bir türün bir sınıf türü olmamasını gerektiriyor mu?
eerorika

2
@eerorika: is_classve is_null_pointerikisi de aynı tür için doğru olamaz. Belirli bir tür için birincil tür kategorisi işlevlerinden yalnızca biri true değerini döndürebilir.
Nicol Bolas

Yanıtlar:


20

Nullptr'in nasıl çalıştığını merak ediyorum.

Mümkün olan en basit şekilde çalışır: fiat tarafından . C ++ standardı çalıştığını söylüyor çünkü çalışıyor ve C ++ standardı uygulamaların bu şekilde çalışması gerektiğini söylüyor .

C ++ dilinin kurallarını kullanarak uygulamanın imkansız olduğunu bilmek önemlidir std::nullptr_t. Boş bir işaretçi sabit tipinden std::nullptr_tbir işaretçiye dönüştürme kullanıcı tanımlı bir dönüşüm değildir. Bu, boş bir işaretçi sabitinden bir işaretçiye, daha sonra kullanıcı tanımlı bir dönüşümden başka bir türe geçebileceğiniz anlamına gelir.

nullptr_tSınıf olarak uygularsanız bu mümkün değildir . Dönüşüm işleçleri, kullanıcı tanımlı dönüşümleri temsil eder ve C ++ 'ın örtük dönüşüm sırası kuralları, bu tür bir dizide birden fazla kullanıcı tanımlı dönüşüme izin vermez.

Bu nedenle, yayınladığınız kod hoş bir yaklaşımdır std::nullptr_t, ancak bundan başka bir şey değildir. Türün meşru bir uygulaması değildir. Bu, derleyicinin uygun bir destek sağlamasından önce, derleyicinin daha eski bir sürümünden (geriye dönük uyumluluk nedenleriyle bırakılmıştır) std::nullptr_t. Bunu gerçeğiyle görebilirsiniz #defines nullptrC ++ 11 söylerken nullptrbir olan anahtar değil, bir makro.

C ++ uygulayamaz std::nullptr_t, C ++ uygulayamadığı gibi intveya void*. Sadece uygulama bu şeyleri uygulayabilir. Onu "temel bir tür" yapan şey budur; dilin bir parçası .


değeri, (void *) 0 ile aynı şekilde integral tipe dönüştürülebilir, ancak geriye doğru değil;

Orada örtülü hiçbir dönüşüm entegre tip bir boş gösterici katsayısına sahiptir. 0Bir integral tipine dönüşüm var , ama bunun nedeni tamsayı değişmez sıfır, yani ... bir tamsayı.

nullptr_tedilebilir döküm (aracılığıyla bir tamsayı türüne reinterpret_cast), ancak yalnızca örtük işaretçilere ve dönüştürülebilir bool.


4
@Wyck: " fiat "
Nicol

"C ++ dilinin kurallarını kullanarak std :: nullptr_t uygulamak imkansız" ile kastedilen nedir? Bir C ++ derleyicisi tamamen C ++ kendisi yazılamaz anlamına mı geliyor (değil tahmin ediyorum)?
northerner

3
@northerner: Yani gerekli davranışa tam olarak eşdeğer bir tür yazamazsınız std::nullptr_t. Tıpkı gereken davranışa tam olarak eşdeğer bir tür yazamayacağınız gibi int. Yaklaşabilirsiniz, ancak yine de önemli farklılıklar olacaktır. Ve is_classbu tür özellik dedektörlerinden bahsetmiyorum , türünüzün kullanıcı tanımlı olduğunu ortaya koyuyor. Dilin kurallarını kullanarak kopyalayamayacağınız temel türlerin gerekli davranışı hakkında şeyler vardır.
Nicol Bolas

1
Sadece bir kelime oyunu. "C ++ uygulayamaz nullptr_t" dediğinde çok geniş konuşuyorsun. Ve "sadece uygulama onu uygulayabilir" demek yalnızca meseleleri karıştırır. Ne demek yani nullptr_t"hayata olamaz C ++ kütüphanesi olduğundan, baz dilin 's parçası.
Spencer

1
@Spencer: Hayır, tam olarak söylediklerimi kastediyorum: C ++ dili, yapılması gereken her şeyi yapan bir tür uygulamak için kullanılamaz std::nullptr_t. Tıpkı C ++ gibi dil, intyapılması gereken her şeyi yapan bir türü uygulayamaz .
Nicol Bolas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.