nullptr คืออะไร


570

ตอนนี้เรามี C ++ 11 พร้อมคุณสมบัติใหม่มากมาย อันใหม่ที่น่าสนใจและสับสน (อย่างน้อยสำหรับฉัน) คือสิ่งใหม่nullptrเป็นใหม่

ไม่จำเป็นสำหรับแมโครที่น่ารังเกียจอีกต่อไปNULLแล้ว

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

ถึงกระนั้นฉันก็ยังไม่ได้nullptrผล ตัวอย่างเช่นบทความ Wikipediaพูดว่า:

C ++ 11 แก้ไขสิ่งนี้โดยการแนะนำคำสำคัญใหม่เพื่อใช้เป็นค่าคงที่ตัวชี้โมฆะที่แตกต่าง: nullptr มันเป็นประเภท nullptr_tซึ่งสามารถแปลงได้โดยปริยายและสามารถเทียบได้กับชนิดตัวชี้หรือชนิดตัวชี้ไปยังสมาชิก มันไม่สามารถเปลี่ยนแปลงได้โดยปริยายหรือเทียบเคียงได้กับชนิดอินทิกรัลยกเว้นสำหรับบูล

มันเป็นคำหลักและตัวอย่างของประเภทได้อย่างไร

นอกจากนี้คุณยังมีตัวอย่างอีก (นอกเหนือจาก Wikipedia) ซึ่งnullptrดีกว่าเก่า0หรือไม่


23
ข้อเท็จจริงที่เกี่ยวข้อง: nullptrนอกจากนี้ยังใช้เพื่อแสดงการอ้างอิงแบบ null สำหรับการจัดการที่จัดการใน C ++ / CLI
Mehrdad Afshari

3
เมื่อใช้ Visual C ++ โปรดจำไว้ว่าถ้าคุณใช้ nullptr ด้วยรหัส native C / C ++ จากนั้นคอมไพล์ด้วยตัวเลือกคอมไพเลอร์ / clr คอมไพเลอร์ไม่สามารถระบุได้ว่า nullptr บ่งชี้ว่าเป็นตัวชี้ null หรือการจัดการ null ในการทำให้เจตนาของคุณชัดเจนต่อคอมไพเลอร์ให้ใช้ nullptr เพื่อระบุค่าที่มีการจัดการหรือ __nullptr เพื่อระบุค่าดั้งเดิม Microsoft ได้ใช้สิ่งนี้เป็นส่วนเสริม
cseder

6
มีการnullptr_tรับประกันว่าจะมีเพียงสมาชิกคนหนึ่งnullptr? ดังนั้นหากฟังก์ชั่นกลับมาnullptr_tแล้วคอมไพเลอร์รู้อยู่แล้วว่าค่าใดจะถูกส่งกลับโดยไม่คำนึงถึงเนื้อหาของฟังก์ชัน?
Aaron McDaid

8
@AaronMcDaid std::nullptr_tสามารถ instantiated แต่ทุกกรณีจะเหมือนกับเพราะประเภทถูกกำหนดให้เป็นnullptr typedef decltype(nullptr) nullptr_tฉันเชื่อว่าเหตุผลหลักที่มีอยู่ประเภทคือฟังก์ชั่นสามารถโหลดมากเกินไปโดยเฉพาะเพื่อจับnullptrถ้าจำเป็น ดูที่นี่สำหรับตัวอย่าง
Justin Time - Reinstate Monica

5
0 ไม่เคยเป็นตัวชี้โมฆะตัวชี้โมฆะเป็นตัวชี้ที่สามารถรับได้โดยการหล่อ ศูนย์ตัวอักษรกับชนิดของตัวชี้และมันไม่ได้ชี้ไปที่วัตถุใด ๆที่มีอยู่ตามคำนิยาม
Swift - Friday Pie

คำตอบ:


403

มันเป็นคำหลักและตัวอย่างของประเภทได้อย่างไร

มันไม่น่าแปลกใจ ทั้งสองtrueและfalseเป็นคำหลักและเป็นตัวอักษรพวกเขามีประเภท ( bool) nullptrเป็นตัวชี้ประเภทที่แท้จริงstd::nullptr_tและเป็นค่าที่แพร่หลาย (คุณไม่สามารถใช้ที่อยู่ของมันได้&)

  • 4.10เกี่ยวกับการแปลงตัวชี้บอกว่า prvalue ประเภทเป็นค่าคงที่ชี้โมฆะและที่สำคัญคงชี้โมฆะสามารถแปลงเป็นstd::nullptr_t std::nullptr_tไม่อนุญาตให้ไปในทิศทางตรงกันข้าม สิ่งนี้อนุญาตให้โอเวอร์โหลดฟังก์ชันสำหรับพอยน์เตอร์และจำนวนเต็มและส่งผ่านnullptrเพื่อเลือกเวอร์ชันพอยน์เตอร์ ผ่านNULLหรือ0เลือกintเวอร์ชันอย่างสับสน

  • การส่งnullptr_tไปยังอินทิกรัลชนิดจำเป็นต้องมีreinterpret_castและมีความหมายเหมือนกับการส่ง(void*)0ไปยังอินทิกรัลประเภท reinterpret_castไม่สามารถแปลงnullptr_tประเภทตัวชี้ใด ๆ static_castพึ่งพาการแปลงนัยถ้าเป็นไปได้หรือการใช้งาน

  • มาตรฐานกำหนดว่าผู้ใดsizeof(nullptr_t)sizeof(void*)


โอ้หลังจากดูแล้วฉันคิดว่าตัวดำเนินการตามเงื่อนไขไม่สามารถแปลง 0 เป็น nullptr ในกรณีเช่นcond ? nullptr : 0;นี้ได้ ลบออกจากคำตอบของฉัน
Johannes Schaub - litb

88
โปรดทราบว่าNULLไม่รับประกันว่าจะเป็น0เช่นนั้น มันอาจเป็นไปได้0Lว่าในกรณีที่การเรียกร้องที่void f(int); void f(char *);จะคลุมเครือ nullptrมักจะเข้าข้างรุ่นตัวชี้และไม่เคยเรียกintหนึ่ง นอกจากนี้โปรดทราบว่าnullptr สามารถแปลงเป็นbool(ร่างบอกว่าที่4.12)
Johannes Schaub - litb

@litb: ดังนั้นเกี่ยวกับ f (int) และ f (void *) - f (0) จะยังคงคลุมเครือหรือไม่
Steve Folly

27
@ Steve ไม่มีที่จะเรียกintรุ่น แต่f(0L)ไม่ชัดเจนเพราะlong -> intตลอดจนlong -> void*เป็นทั้งค่าใช้จ่ายอย่างเท่าเทียมกัน ดังนั้นถ้า NULL อยู่0Lในคอมไพเลอร์ของคุณการโทรf(NULL)จะไม่ชัดเจนเนื่องจากทั้งสองฟังก์ชั่น ไม่nullptrแน่นอนด้วย
Johannes Schaub - litb

2
@SvenS จะต้องไม่ถูกกำหนดเหมือน(void*)0ใน C ++ แต่สามารถนิยามเป็นค่าคงที่ตัวชี้โมฆะใดก็ได้ซึ่งค่าคงที่อินทิกรัลใด ๆ ที่มีค่า 0 และnullptrเติมเต็ม ดังนั้นแน่นอนที่สุดไม่ได้จะแต่สามารถ (คุณลืมที่จะ ping ฉัน btw .. )
Deduplicator

60

จากnullptr: ตัวชี้ชนิด Null ที่ปลอดภัยและชัดเจน :

คำหลัก C ++ 09 nullptr ใหม่กำหนดค่าคงที่ rvalue ที่ทำหน้าที่เป็นตัวชี้ null แบบสากลแทนที่ตัวอักษร buggy และตัวอักษรที่พิมพ์น้อย 0 และแมโคร NULL ที่น่าอับอาย nullptr จึงหมดสิ้นไปกว่า 30 ปีของความอับอายความคลุมเครือและข้อบกพร่อง ส่วนต่อไปนี้นำเสนอสิ่งอำนวยความสะดวก nullptr และแสดงว่ามันสามารถแก้ไขอาการเจ็บป่วยของ NULL และ 0 ได้อย่างไร

การอ้างอิงอื่น ๆ :


17
C ++ 09? มันไม่ได้ถูกอ้างถึงว่าเป็น C ++ 0x ก่อน ส.ค. 2554 หรือ
Michael Dorst

2
@ anthropomorphic นั่นคือจุดประสงค์ของมัน ใช้ C ++ 0x ขณะที่ยังทำงานอยู่เนื่องจากยังไม่ทราบว่าจะแล้วเสร็จในปี 2008 หรือ 2009 โปรดทราบว่าจริง ๆ แล้วมันกลายเป็น C ++ 0B หมายถึง C ++ 11 ดูstroustrup.com/C++11FAQ.html
mxmlnkn

44

ทำไม nullptr ใน C ++ 11? มันคืออะไร? ทำไมค่า NULL ไม่เพียงพอ?

ผู้เชี่ยวชาญ C ++ อเล็กซ์อัลเลนพูดว่าที่นี่อย่างสมบูรณ์แบบ (การเน้นของฉันเพิ่มในตัวหนา):

... ลองจินตนาการว่าคุณมีการประกาศฟังก์ชันสองรายการต่อไปนี้:

void func(int n); 
void func(char *s);

func( NULL ); // guess which function gets called?

แม้ว่ามันจะดูเหมือนว่าฟังก์ชั่นที่สองจะถูกเรียก - แต่คุณผ่านสิ่งที่ดูเหมือนจะเป็นตัวชี้ - มันเป็นฟังก์ชั่นแรกที่จะถูกเรียก! ปัญหาคือเนื่องจาก NULL เป็น 0 และ 0 เป็นจำนวนเต็ม func รุ่นแรกจะถูกเรียกแทน นี่คือสิ่งที่ใช่ไม่ใช่ไม่เกิดขึ้นตลอดเวลา แต่เมื่อมันเกิดขึ้นมันน่าหงุดหงิดและสับสนเป็นอย่างมาก หากคุณไม่ทราบรายละเอียดว่าเกิดอะไรขึ้นมันอาจดูเหมือนคอมไพเลอร์บั๊ก คุณลักษณะภาษาที่ดูเหมือนว่าตัวรวบรวมข้อผิดพลาดคือไม่ใช่สิ่งที่คุณต้องการ

ป้อน nullptr ใน C ++ 11, nullptr เป็นคีย์เวิร์ดใหม่ที่สามารถ (และควร!) เพื่อใช้แทนพอยน์เตอร์พอยน์เตอร์ กล่าวอีกนัยหนึ่งไม่ว่าคุณจะเขียน NULL ที่ไหนมาก่อนคุณควรใช้ nullptr แทน ไม่มีความชัดเจนสำหรับคุณโปรแกรมเมอร์ (ทุกคนรู้ว่า NULL หมายถึงอะไร) แต่ชัดเจนกว่ากับคอมไพเลอร์ซึ่งจะไม่เห็น 0s ทุกที่ที่ใช้มีความหมายพิเศษเมื่อใช้เป็นตัวชี้

อัลเลนจบบทความของเขาด้วย:

โดยไม่คำนึงถึงสิ่งทั้งหมด - กฎง่ายๆสำหรับ C ++ 11 คือการเริ่มใช้nullptrเมื่อใดก็ตามที่คุณเคยใช้เป็นอย่างอื่นNULLในอดีต

(คำพูดของฉัน):

สุดท้ายอย่าลืมว่านั่นnullptrคือวัตถุ - คลาส มันสามารถใช้งานได้ทุกNULLที่ใช้มาก่อน แต่ถ้าคุณต้องการชนิดด้วยเหตุผลบางอย่างก็ชนิดสามารถนำมาสกัดด้วยdecltype(nullptr)หรืออธิบายโดยตรงstd::nullptr_tซึ่งเป็นเพียงของtypedefdecltype(nullptr)

อ้างอิง:

  1. Cprogramming.com: ประเภทที่ดีขึ้นใน C ++ 11 - nullptr, enum คลาส (enumerations ที่พิมพ์ได้อย่างมาก) และ cstdint
  2. https://en.cppreference.com/w/cpp/language/decltype
  3. https://en.cppreference.com/w/cpp/types/nullptr_t

2
ฉันต้องบอกว่าคำตอบของคุณถูกประเมินต่ำเกินไปมันง่ายที่จะเข้าใจผ่านตัวอย่างของคุณ
mss

37

เมื่อคุณมีฟังก์ชั่นที่สามารถรับพอยน์เตอร์มากกว่าหนึ่งประเภทการโทรด้วยมันNULLจะคลุมเครือ วิธีการนี้จะทำงานรอบในขณะนี้คือ hacky มากโดยการยอมรับเป็น int 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); }
};

ในC++11คุณจะสามารถโอเวอร์โหลดnullptr_tเพื่อที่ptr<T> p(42);จะเป็นข้อผิดพลาดในการรวบรวมมากกว่าเวลาassertทำงาน

ptr(std::nullptr_t) : p_(nullptr)  {  }

เกิดอะไรขึ้นถ้าNULLมีการกำหนดเป็น0L?
LF

9

nullptrไม่สามารถกำหนดให้กับประเภทอินทิกรัลเช่นintแต่ประเภทพอยน์เตอร์เท่านั้น ไม่ว่าจะเป็นตัวชี้ชนิดในตัวเช่นint *ptrหรือตัวชี้สมาร์ทเช่นstd::shared_ptr<T>

ฉันเชื่อว่านี่เป็นความแตกต่างที่สำคัญเพราะNULLยังสามารถกำหนดให้กับทั้งชนิดที่หนึ่งและตัวชี้ตามที่NULLเป็นแมโครที่ขยาย0ซึ่งสามารถทำหน้าที่เป็นทั้งค่าเริ่มต้นสำหรับintตัวชี้และ


โปรดทราบว่าคำตอบนี้ผิด ไม่รับประกันว่าจะขยายได้ถึงNULL 0
LF

6

นอกจากนี้คุณยังมีตัวอย่างอีก (ข้างๆ Wikipedia) ซึ่งnullptrดีกว่ารุ่นเก่า 0 หรือไม่

ใช่. นอกจากนี้ยังเป็นตัวอย่างในโลกแห่งความเป็นจริง (ประยุกต์) ที่เกิดขึ้นในรหัสการผลิตของเรา มีความโดดเด่นเพียงอย่างเดียวเนื่องจาก gcc สามารถออกคำเตือนเมื่อทำการคอมไพล์ไปยังแพลตฟอร์มที่มีความกว้างรีจิสเตอร์ต่างกัน (ยังไม่แน่ใจว่าทำไมเมื่อการคอมไพล์จาก x86_64 ถึง x86 เตือนwarning: converting to non-pointer type 'int' from NULL):

พิจารณารหัสนี้ (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;
}

มันให้ผลลัพธ์นี้:

(a == pb): 1
(a == 0): 0
(a == NULL): 0
(a == null): 1

ฉันไม่เห็นวิธีการปรับปรุงนี้เมื่อใช้ nullptr (และ C ++ 11) หากคุณตั้งค่า pb เป็น nullptr การเปรียบเทียบครั้งแรกจะประเมินว่าเป็นจริง (ในขณะที่เปรียบเทียบแอปเปิ้ลกับลูกแพร์ .. ) กรณีที่สองยิ่งแย่กว่านี้: ถ้าคุณเปรียบเทียบ a เป็น nullptr มันจะแปลง a เป็น B * จากนั้นจะประเมินเป็นจริงอีกครั้ง (ก่อนที่จะถูกส่งไปยัง bool และ expr ประเมินว่าเป็นเท็จ) สิ่งทั้งหมดทำให้ฉันนึกถึง JavaScript และฉันสงสัยว่าเราจะได้ === ใน C ++ ในอนาคต :(
Nils

5

ภาษาอื่นมีคำที่สงวนไว้ซึ่งเป็นอินสแตนซ์ของประเภท Python เช่น:

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

นี่เป็นการเปรียบเทียบที่ค่อนข้างใกล้ชิดเพราะNoneโดยทั่วไปแล้วจะใช้สำหรับบางสิ่งที่ไม่ได้มีการปรับ แต่ในเวลาเดียวกันการเปรียบเทียบเช่นเป็นNone == 0เท็จ

ในทางกลับกันใน C ธรรมดา NULL == 0จะคืนค่า IIRC ที่แท้จริงเพราะNULLเป็นเพียงแมโครกลับ 0 ซึ่งมักจะเป็นที่อยู่ที่ไม่ถูกต้อง (AFAIK)


4
NULLเป็นมาโครที่ขยายไปเป็นศูนย์การโยนค่าคงที่ไปยังตัวชี้จะสร้างตัวชี้โมฆะ ตัวชี้โมฆะไม่จำเป็นต้องเป็นศูนย์ (แต่มักจะเป็น), ศูนย์ไม่ได้อยู่เสมอที่ไม่ถูกต้องและโยนศูนย์ที่ไม่คงที่ไปยังตัวชี้ไม่จำเป็นต้องเป็นโมฆะและโยนชี้ไปที่ จำนวนเต็มไม่ต้องเป็นศูนย์ ฉันหวังว่าฉันเข้าใจถูกต้องแล้วโดยไม่ลืมอะไรเลย การอ้างอิง: c-faq.com/null/null2.html
ซามูเอลเอ็ดวินวอร์ด

3

มันเป็นคำหลักเพราะมาตรฐานจะระบุเช่นนี้ ;-) ตามแบบร่างสาธารณะล่าสุด (n2914)

2.14.7 ตัวอักษรตัวชี้ [lex.nullptr]

pointer-literal:
nullptr

nullptrอักษรตัวชี้เป็นคำสำคัญ มันเป็น rvalue std::nullptr_tประเภท

มันมีประโยชน์เพราะมันไม่ได้แปลงเป็นค่าปริยาย


2

สมมติว่าคุณมีฟังก์ชั่น (f) ซึ่งโอเวอร์โหลดเพื่อรับทั้ง int และ char * ก่อน C ++ 11 ถ้าคุณต้องการเรียกมันด้วยพอยน์เตอร์โมฆะและคุณใช้ NULL (เช่นค่า 0) จากนั้นคุณจะเรียกมันว่าโอเวอร์โหลดสำหรับ int:

void f(int);
void f(char*);

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

นี่อาจไม่ใช่สิ่งที่คุณต้องการ C ++ 11 แก้ปัญหานี้ด้วย nullptr; ตอนนี้คุณสามารถเขียนสิ่งต่อไปนี้:

void g()
{
  f(nullptr); //calls f(char*)
}

1

ก่อนอื่นขอให้คุณใช้สิ่งที่ไม่ซับซ้อน 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เป็นตัวอย่างบอบบางของReturn Type Resolver idiom เพื่ออนุมานตัวชี้โมฆะของประเภทที่ถูกต้องโดยอัตโนมัติขึ้นอยู่กับประเภทของอินสแตนซ์ที่มันได้รับมอบหมาย

int *ptr = nullptr;                // OK
void (C::*method_ptr)() = nullptr; // OK
  • อย่างที่คุณสามารถด้านบนเมื่อnullptrถูกกำหนดให้กับตัวชี้จำนวนเต็มการintสร้างอินสแตนซ์ประเภทของฟังก์ชันการแปลงเทมเพลทถูกสร้างขึ้น และเช่นเดียวกันสำหรับตัวชี้วิธี
  • ด้วยการใช้ประโยชน์จากฟังก์ชั่นเทมเพลตเรากำลังสร้างตัวชี้โมฆะประเภทที่เหมาะสมทุกครั้งที่เราทำการกำหนดประเภทใหม่
  • เนื่องจากnullptrเป็นตัวอักษรจำนวนเต็มที่มีค่าเป็นศูนย์คุณไม่สามารถใช้ที่อยู่ของที่อยู่ที่เราดำเนินการได้โดยการลบ & โอเปอเรเตอร์

ทำไมเราต้องการnullptrตั้งแต่แรก?

  • คุณเห็นแบบดั้งเดิมNULLมีปัญหากับมันดังนี้:

1️⃣การแปลงโดยนัย

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

2️⃣ฟังก์ชั่นการโทรคลุมเครือ

void func(int) {}
void func(int*){}
void func(bool){}

func(NULL);     // Which one to call?
  • การรวบรวมก่อให้เกิดข้อผิดพลาดต่อไปนี้:
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 โอเวอร์โหลด

struct String
{
    String(uint32_t)    {   /* size of string */    }
    String(const char*) {       /* string */        }
};

String s1( NULL );
String s2( 5 );
  • ในกรณีเช่นนี้คุณต้องใช้การส่งที่ชัดเจน (เช่น,  String s((char*)0)).

0

0 เคยเป็นค่าจำนวนเต็มเท่านั้นที่สามารถใช้เป็น initializer แบบไม่มีคาสต์สำหรับพอยน์เตอร์: คุณไม่สามารถเริ่มต้นพอยน์เตอร์ด้วยค่าจำนวนเต็มอื่น ๆ โดยไม่ต้องคาสต์ คุณสามารถพิจารณา 0 เป็น consexpr singleton syntactically คล้ายกับตัวอักษรจำนวนเต็ม มันสามารถเริ่มต้นตัวชี้หรือจำนวนเต็มใด ๆ แต่น่าแปลกใจที่คุณจะพบว่ามันไม่มีประเภทที่แตกต่าง: intมันเป็น ดังนั้นทำไม 0 สามารถเริ่มต้นตัวชี้และ 1 ไม่สามารถ? คำตอบที่ใช้งานได้จริงคือเราต้องการวิธีกำหนดค่าตัวชี้เป็นโมฆะและการแปลงโดยตรงintไปยังตัวชี้โดยปริยายนั้นเกิดข้อผิดพลาดได้ง่าย ดังนั้น 0 จึงกลายเป็นสัตว์ประหลาดแปลก ๆ ออกมาจากยุคก่อนประวัติศาสตร์ nullptrถูกเสนอให้เป็นตัวแทน constexpr ซิงเกิลจริงของค่า null เพื่อเริ่มต้นพอยน์เตอร์ มันไม่สามารถใช้ในการเริ่มต้นจำนวนเต็มโดยตรงและกำจัดความคลุมเครือที่เกี่ยวข้องกับการกำหนดNULLในแง่ของ 0nullptrอาจถูกกำหนดให้เป็นห้องสมุดโดยใช้ไวยากรณ์ std แต่ดูเหมือนว่าจะเป็นองค์ประกอบหลักที่ขาดหายไป NULLจะเลิกตอนนี้ในความโปรดปรานของเว้นแต่ห้องสมุดบางส่วนตัดสินใจที่จะกำหนดเป็นnullptrnullptr


-1

นี่คือส่วนหัว LLVM

// -*- C++ -*-
//===--------------------------- __nullptr --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP_NULLPTR
#define _LIBCPP_NULLPTR

#include <__config>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif

#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

#endif  // _LIBCPP_NULLPTR

(ข้อเสนอที่ดีสามารถค้นพบได้อย่างรวดเร็วgrep -r /usr/include/*`)

สิ่งหนึ่งที่กระโดดออกมาก็คือตัวดำเนินการ*โอเวอร์โหลด (การส่งคืน 0 นั้นเป็นมิตรมากกว่าการแบ่ง ... ) สิ่งหนึ่งคือมันดูไม่เข้ากันได้กับการจัดเก็บที่อยู่ที่ทุกคน ซึ่งเมื่อเทียบกับวิธีการใช้สลิงเป็นโมฆะและส่งผลให้ค่า NULL ไปยังพอยน์เตอร์ปกติเป็นค่าของ Sentinel จะช่วยลด "ไม่เคยลืมมันอาจเป็นระเบิด"


-2

NULL ไม่จำเป็นต้องเป็น 0 ตราบใดที่คุณใช้เสมอ NULL และไม่เคยเป็น 0, NULL สามารถเป็นค่าใด ๆ ได้ สมมติว่าคุณเขียนโปรแกรม von Neuman Microcontroller ที่มีหน่วยความจำแบบแบนที่มี vektors ขัดจังหวะที่ 0 ถ้า NULL เป็น 0 และบางอย่างเขียนที่ NULL Pointer the Microcontroller ล่ม ถ้า NULL บอกว่า 1024 และที่ 1024 มีตัวแปรที่สงวนไว้การเขียนจะไม่ทำงานผิดพลาดและคุณสามารถตรวจจับการกำหนด NULL Pointer ได้จากภายในโปรแกรม สิ่งนี้ไม่มีประโยชน์บนพีซี แต่สำหรับยานสำรวจอวกาศอุปกรณ์ทางการแพทย์หรือทางการแพทย์เป็นสิ่งสำคัญที่จะไม่เกิดปัญหา


2
ค่าจริงของตัวชี้โมฆะในหน่วยความจำอาจไม่ใช่ศูนย์ แต่ C (และ C ++) มาตรฐานสั่งคอมไพเลอร์เพื่อแปลงอินทิกรัล 0 ตัวอักษรเป็นตัวชี้โมฆะ
bzim
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.