csdnceshi65
larry*wei
2009-08-15 16:47
采纳率: 0%
浏览 942

Nullptr 到底是什么?

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 macro NULL.

int* x = nullptr;
myclass* obj = nullptr;

Still, I am not getting how nullptr works. For example, Wikipedia article says:

C++11 corrects this by introducing a new keyword to serve as a distinguished null pointer constant: nullptr. It is of type nullptr_t, which is implicitly convertible and comparable to any pointer type or pointer-to-member type. It is not implicitly convertible or comparable to integral types, except for bool.

How is it a keyword and an instance of a type?

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

转载于:https://stackoverflow.com/questions/1282295/what-exactly-is-nullptr

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

11条回答 默认 最新

  • csdnceshi77
    狐狸.fox 2009-08-15 17:06
    已采纳

    How is it a keyword and an instance of a type?

    This isn't surprising. Both true and false are keywords and as literals they have a type ( bool ). nullptr is a pointer literal of type std::nullptr_t, and it's a prvalue (you cannot take the address of it using &).

    • 4.10 about pointer conversion says that a prvalue of type std::nullptr_t is a null pointer constant, and that an integral null pointer constant can be converted to std::nullptr_t. The opposite direction is not allowed. This allows overloading a function for both pointers and integers, and passing nullptr to select the pointer version. Passing NULL or 0 would confusingly select the int version.

    • A cast of nullptr_t to an integral type needs a reinterpret_cast, and has the same semantics as a cast of (void*)0 to an integral type (mapping implementation defined). A reinterpret_cast cannot convert nullptr_t to any pointer type. Rely on the implicit conversion if possible or use static_cast.

    • The Standard requires that sizeof(nullptr_t) be sizeof(void*).

    点赞 评论
  • csdnceshi56
    lrony* 2009-08-15 16:52

    Well, other languages have reserved words that are instances of types. Python, for instance:

    >>> None = 5
      File "<stdin>", line 1
    SyntaxError: assignment to None
    >>> type(None)
    <type 'NoneType'>
    

    This is actually a fairly close comparison because None is typically used for something that hasn't been intialized, but at the same time comparisons such as None == 0 are false.

    On the other hand, in plain C, NULL == 0 would return true IIRC because NULL is just a macro returning 0, which is always an invalid address (AFAIK).

    点赞 评论
  • csdnceshi69
    YaoRaoLov 2009-08-15 17:00

    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.

    点赞 评论
  • csdnceshi69
    YaoRaoLov 2009-08-15 17:02

    From nullptr: A Type-safe and Clear-Cut Null Pointer:

    The new C++09 nullptr keyword designates an rvalue constant that serves as a universal null pointer literal, replacing the buggy and weakly-typed literal 0 and the infamous NULL macro. nullptr thus puts an end to more than 30 years of embarrassment, ambiguity, and bugs. The following sections present the nullptr facility and show how it can remedy the ailments of NULL and 0.

    Other references:

    点赞 评论
  • csdnceshi72
    谁还没个明天 2009-08-16 06:46

    When you have a function that can receive pointers to more than one type, calling it with NULL is ambiguous. The way this is worked around now is very hacky by accepting an int and assuming it's NULL.

    template <class T>
    class ptr {
        T* p_;
        public:
            ptr(T* p) : p_(p) {}
    
            template <class U>
            ptr(U* u) : p_(dynamic_cast<T*>(u)) { }
    
            // Without this ptr<T> p(NULL) would be ambiguous
            ptr(int null) : p_(NULL)  { assert(null == NULL); }
    };
    

    In C++11 you would be able to overload on nullptr_t so that ptr<T> p(42); would be a compile-time error rather than a run-time assert.

    ptr(std::nullptr_t) : p_(nullptr)  {  }
    
    点赞 评论
  • csdnceshi59
    ℙℕℤℝ 2013-01-29 13:12

    nullptr can't be assigned to an integral type such as an int but only a type pointer; either a built-in pointer type such as int *ptr or a smart pointer such as std::shared_ptr<T>

    I believe this is an important distinction because NULL can still be assigned to an integral type and a pointer as NULL is a macro expanded to 0 which can serve as both an initial value for an int as well as a pointer.

    点赞 评论
  • weixin_41568196
    撒拉嘿哟木头 2013-09-25 20:31

    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
    
    点赞 评论
  • csdnceshi76
    斗士狗 2015-07-31 20:31

    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.

    点赞 评论
  • weixin_41568196
    撒拉嘿哟木头 2017-10-20 21:14

    Let's say that you have a function (f) which is overloaded to take both int and char*. Before C++ 11, If you wanted to call it with a null pointer, and you used NULL (i.e. the value 0), then you would call the one overloaded for int:

    void f(int);
    void f(char*);
    
    void g() 
    {
      f(0); // Calls f(int).
      f(NULL); // Equals to f(0). Calls f(int).
    }
    

    This is probably not what you wanted. C++11 solves this with nullptr; Now you can write the following:

    void g()
    {
      f(nullptr); //calls f(char*)
    }
    
    点赞 评论
  • csdnceshi63
    elliott.david 2018-03-07 06:18

    Why nullptr in C++11? What is it? Why is NULL not sufficient?

    C++ expert Alex Allain says it perfectly here:

    "...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."

    点赞 评论
  • csdnceshi50
    三生石@ 2018-06-16 07:33

    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.

    点赞 评论

相关推荐