What exactly is nullptr?

前端 未结 14 2367
无人及你
无人及你 2020-11-22 01:12

We now have C++11 with many new features. An interesting and confusing one (at least for me) is the new nullptr.

Well, no need anymore for the nasty mac

相关标签:
14条回答
  • 2020-11-22 01:31

    0 used to be the only integer value that could be used as a cast-free initializer for pointers: you can not initialize pointers with other integer values without a cast. You can consider 0 as a consexpr singleton syntactically similar to an integer literal. It can initiate any pointer or integer. But surprisingly, you'll find that it has no distinct type: it is an int. So how come 0 can initialize pointers and 1 cannot? A practical answer was we need a means of defining pointer null value and direct implicit conversion of int to a pointer is error-prone. Thus 0 became a real freak weirdo beast out of the prehistoric era. nullptr was proposed to be a real singleton constexpr representation of null value to initialize pointers. It can not be used to directly initialize integers and eliminates ambiguities involved with defining NULL in terms of 0. nullptr could be defined as a library using std syntax but semantically looked to be a missing core component. NULL is now deprecated in favor of nullptr, unless some library decides to define it as nullptr.

    0 讨论(0)
  • 2020-11-22 01:34

    NULL need not to be 0. As long you use always NULL and never 0, NULL can be any value. Asuming you programme a von Neuman Microcontroller with flat memory, that has its interrupt vektors at 0. If NULL is 0 and something writes at a NULL Pointer the Microcontroller crashes. If NULL is lets say 1024 and at 1024 there is a reserved variable, the write won't crash it, and you can detect NULL Pointer assignments from inside the programme. This is Pointless on PCs, but for space probes, military or medical equipment it is important not to crash.

    0 讨论(0)
  • Why nullptr in C++11? What is it? Why is NULL not sufficient?

    C++ expert Alex Allain says it perfectly here (my emphasis added in bold):

    ...imagine you have the following two function declarations:

    void func(int n); 
    void func(char *s);
    
    func( NULL ); // guess which function gets called?
    

    Although it looks like the second function will be called--you are, after all, passing in what seems to be a pointer--it's really the first function that will be called! The trouble is that because NULL is 0, and 0 is an integer, the first version of func will be called instead. This is the kind of thing that, yes, doesn't happen all the time, but when it does happen, is extremely frustrating and confusing. If you didn't know the details of what is going on, it might well look like a compiler bug. A language feature that looks like a compiler bug is, well, not something you want.

    Enter nullptr. In C++11, nullptr is a new keyword that can (and should!) be used to represent NULL pointers; in other words, wherever you were writing NULL before, you should use nullptr instead. It's no more clear to you, the programmer, (everyone knows what NULL means), but it's more explicit to the compiler, which will no longer see 0s everywhere being used to have special meaning when used as a pointer.

    Allain ends his article with:

    Regardless of all this--the rule of thumb for C++11 is simply to start using nullptr whenever you would have otherwise used NULL in the past.

    (My words):

    Lastly, don't forget that nullptr is an object--a class. It can be used anywhere NULL was used before, but if you need its type for some reason, it's type can be extracted with decltype(nullptr), or directly described as std::nullptr_t, which is simply a typedef of decltype(nullptr).

    References:

    1. Cprogramming.com: Better types in C++11 - nullptr, enum classes (strongly typed enumerations) and cstdint
    2. https://en.cppreference.com/w/cpp/language/decltype
    3. https://en.cppreference.com/w/cpp/types/nullptr_t
    0 讨论(0)
  • 2020-11-22 01:44

    It is a keyword because the standard will specify it as such. ;-) According to the latest public draft (n2914)

    2.14.7 Pointer literals [lex.nullptr]

    pointer-literal:
    nullptr
    

    The pointer literal is the keyword nullptr. It is an rvalue of type std::nullptr_t.

    It's useful because it does not implicitly convert to an integral value.

    0 讨论(0)
  • 2020-11-22 01:47

    Also, do you have another example (beside the Wikipedia one) where nullptr is superior to good old 0?

    Yes. It's also a (simplified) real-world example that occurred in our production code. It only stood out because gcc was able to issue a warning when crosscompiling to a platform with different register width (still not sure exactly why only when crosscompiling from x86_64 to x86, warns warning: converting to non-pointer type 'int' from NULL):

    Consider this code (C++03):

    #include <iostream>
    
    struct B {};
    
    struct A
    {
        operator B*() {return 0;}
        operator bool() {return true;}
    };
    
    int main()
    {
        A a;
        B* pb = 0;
        typedef void* null_ptr_t;
        null_ptr_t null = 0;
    
        std::cout << "(a == pb): " << (a == pb) << std::endl;
        std::cout << "(a == 0): " << (a == 0) << std::endl; // no warning
        std::cout << "(a == NULL): " << (a == NULL) << std::endl; // warns sometimes
        std::cout << "(a == null): " << (a == null) << std::endl;
    }
    

    It yields this output:

    (a == pb): 1
    (a == 0): 0
    (a == NULL): 0
    (a == null): 1
    
    0 讨论(0)
  • 2020-11-22 01:47

    Let me first give you an implementation of unsophisticated nullptr_t

    struct nullptr_t 
    {
        void operator&() const = delete;  // Can't take address of nullptr
    
        template<class T>
        inline operator T*() const { return 0; }
    
        template<class C, class T>
        inline operator T C::*() const { return 0; }
    };
    
    nullptr_t nullptr;
    

    nullptr is a subtle example of Return Type Resolver idiom to automatically deduce a null pointer of the correct type depending upon the type of the instance it is assigning to.

    int *ptr = nullptr;                // OK
    void (C::*method_ptr)() = nullptr; // OK
    
    • As you can above, when nullptr is being assigned to an integer pointer, a int type instantiation of the templatized conversion function is created. And same goes for method pointers too.
    • This way by leveraging template functionality, we are actually creating the appropriate type of null pointer every time we do, a new type assignment.
    • As nullptr is an integer literal with value zero, you can not able to use its address which we accomplished by deleting & operator.

    Why do we need nullptr in the first place?

    • You see traditional NULL has some issue with it as below:

    1️⃣ Implicit conversion

    char *str = NULL; // Implicit conversion from void * to char *
    int i = NULL;     // OK, but `i` is not pointer type
    
    

    2️⃣ Function calling ambiguity

    void func(int) {}
    void func(int*){}
    void func(bool){}
    
    func(NULL);     // Which one to call?
    
    
    • Compilation produces the following error:
    error: call to 'func' is ambiguous
        func(NULL);
        ^~~~
    note: candidate function void func(bool){}
                                  ^
    note: candidate function void func(int*){}
                                  ^
    note: candidate function void func(int){}
                                  ^
    1 error generated.
    compiler exit status 1
    
    

    3️⃣ Constructor overload

    struct String
    {
        String(uint32_t)    {   /* size of string */    }
        String(const char*) {       /* string */        }
    };
    
    String s1( NULL );
    String s2( 5 );
    
    
    • In such cases, you need explicit cast (i.e., String s((char*)0)).
    0 讨论(0)
提交回复
热议问题