คุณใช้ NULL หรือ 0 (ศูนย์) สำหรับตัวชี้ใน C ++ หรือไม่?


194

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

จนถึงวันนี้ผมยังคงใช้เป็นศูนย์เป็นตัวชี้โมฆะ แต่คนรอบ ๆ NULLตัวผมยืนยันในการใช้ ฉันเองไม่เห็นประโยชน์ใด ๆ ในการตั้งชื่อ ( NULL) ให้กับค่าที่มีอยู่ - และเนื่องจากฉันต้องการทดสอบพอยน์เตอร์เป็นค่าความจริง:

if (p && !q)
  do_something();

จากนั้นใช้ศูนย์ทำให้รู้สึกมากขึ้น (เช่นถ้าคุณใช้NULLคุณไม่สามารถใช้อย่างมีเหตุผลp && !q- คุณต้องเปรียบเทียบอย่างชัดเจนNULLเว้นแต่คุณจะถือว่าNULLเป็นศูนย์ในกรณีนี้ทำไมใช้NULL)

มีเหตุผลวัตถุประสงค์ใดที่จะชอบศูนย์มากกว่า NULL (หรือกลับกัน) หรือทั้งหมดเป็นเพียงการตั้งค่าส่วนตัว?

แก้ไข: ฉันควรเพิ่ม (และตั้งใจจะพูด แต่เดิม) ว่าด้วย RAII และข้อยกเว้นฉันไม่ค่อยใช้ตัวชี้ศูนย์ / NULL แต่บางครั้งคุณก็ยังต้องการ


9
รอไม่จำเป็นต้องใช้ตัวชี้ null เพื่อประเมินว่าเป็นเท็จโดยไม่คำนึงว่า null เป็นศูนย์ภายในหรือไม่
Mooing Duck

5
stackoverflow.com/questions/9894013/…และc-faq.com/null/ptrtest.htmlยืนยันสิ่งนี้
Mooing Duck

คำตอบ:


186

นี่คือสิ่งที่ Stroustrup ใช้ในเรื่องนี้: สไตล์ C ++ และคำถามที่พบบ่อยด้านเทคนิค

ใน C ++ นิยามของNULLคือ 0 ดังนั้นจึงมีความแตกต่างทางสุนทรียะเท่านั้น ฉันชอบที่จะหลีกเลี่ยงมาโครดังนั้นฉันจึงใช้ 0 ปัญหาอีกอย่างหนึ่งNULLคือบางครั้งผู้คนเชื่อว่าผิดพลาดว่าแตกต่างจาก 0 และ / หรือไม่ใช่จำนวนเต็ม ในรหัสล่วงหน้ามาตรฐานNULLบางครั้ง / ถูกกำหนดให้กับบางสิ่งที่ไม่เหมาะสมดังนั้นจึงจำเป็นต้องหลีกเลี่ยง นั่นเป็นเรื่องธรรมดาน้อยวันนี้

หากคุณมีการตั้งชื่อตัวชี้โมฆะเรียกว่าnullptr; นั่นคือสิ่งที่มันถูกเรียกใน C ++ 11 จากนั้นnullptrจะเป็นคำหลัก

ที่กล่าวว่าอย่าเหงื่อสิ่งเล็ก ๆ น้อย ๆ


7
Bjarne เขียนสิ่งนี้ก่อน C ++ 0x เริ่มทำงานกับประเภท null ใหม่ มันจะเป็นกรณีที่ NULL จะใช้สำหรับประเภทนี้เมื่อมันพร้อมใช้งานสำหรับแพลตฟอร์มและฉันคิดว่าคุณจะเห็นการเปลี่ยนแปลง C ในฉันทามติทั่วไปเกี่ยวกับเรื่องนี้
Richard Corden

122

มีข้อโต้แย้งเล็กน้อย (ข้อหนึ่งซึ่งค่อนข้างเร็ว) ซึ่งฉันเชื่อว่าตำแหน่งของ Bjarne ขัดแย้งกับเรื่องนี้

  1. เอกสารแสดงเจตจำนง

การใช้NULLช่วยให้สามารถค้นหาโดยใช้งานได้และยังเน้นว่านักพัฒนาซอฟต์แวร์ต้องการใช้NULLตัวชี้โดยไม่คำนึงว่าคอมไพเลอร์ตีความNULLหรือไม่

  1. เกินชี้และ 'int' ค่อนข้างหายาก

ตัวอย่างที่ทุกคนพูดคือ:

void foo(int*);
void foo (int);

void bar() {
  foo (NULL);  // Calls 'foo(int)'
}

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

  1. เครื่องมือวิเคราะห์สามารถช่วยวันนี้!

แม้ในกรณีที่ไม่มี C ++ 0x มีเครื่องมือที่พร้อมใช้งานทุกวันนี้ที่ตรวจสอบว่าNULLมีการใช้งานสำหรับพอยน์เตอร์และ0มีการใช้งานสำหรับประเภทที่สำคัญ

  1. C ++ 11จะมีใหม่std::nullptr_tประเภท

นี่คืออาร์กิวเมนต์ล่าสุดของตาราง ปัญหาของ0และNULLกำลังได้รับการแก้ไขอย่างแข็งขันสำหรับ C ++ 0x และคุณสามารถรับประกันได้ว่าสำหรับทุกการใช้งานที่มีให้NULLสิ่งแรกที่พวกเขาจะทำคือ:

#define NULL  nullptr

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


1
นั่นเป็นจุดที่ค่อนข้างดีฉันต้องยอมรับ ฉันดีใจที่ C ++ 0x จะมีประเภท null ฉันคิดว่าจะทำให้สิ่งต่าง ๆ สะอาดขึ้น
Rob

2
@ ริชาร์ดทำไมไม่ทำตรงกันข้าม คุณสามารถใช้ Meyers nullptr_t จากนั้นเมื่อ 0x เริ่มใช้งานได้คุณลบ#includeและเก็บไว้ในที่ปลอดภัยตลอดทาง
fnieto - Fernando Nieto

15
#define NULL nullptrดูเหมือนว่าอันตราย สำหรับดีขึ้นหรือแย่ลงจำนวนมากของมรดกใช้รหัสโมฆะสำหรับสิ่งอื่น ๆ กว่า 0 ตัวอย่างเช่นจับมักจะถูกนำมาใช้เป็นชนิดหนึ่งบางส่วนและการตั้งค่าให้พวกเขาNULLไม่ได้เป็นเรื่องผิดปกติ ฉันเคยเห็นการใช้งานที่ไม่เหมาะสมเช่นใช้NULLเพื่อตั้งค่าcharเป็นศูนย์
Adrian McCarthy

8
@AdrianMcCarthy: ฉันจะบอกว่ามันเป็นอันตรายหากมีอันตรายจากรหัสรวบรวมอย่างเงียบ ๆ และมีความหมายที่แตกต่างกัน ฉันค่อนข้างแน่ใจว่านี่ไม่ใช่กรณีดังนั้นจริงๆแล้วการตรวจสอบการใช้ NULL ที่ไม่ถูกต้องทั้งหมดจะถูกตรวจพบ
Richard Corden

3
@RichardCorden: อืมสันนิษฐานว่าการใช้งานอื่นของผู้ใช้NULLนั้นไม่ถูกต้อง APIs จำนวนมากมีการใช้งานNULLกับด้ามจับมานานและที่จริงแล้วเป็นการใช้งานเอกสารที่มีหลายตัว มันไม่สามารถนำไปปฏิบัติได้ในทันทีที่จะทำลายสิ่งเหล่านั้นและประกาศว่าพวกเขาทำผิด
Adrian McCarthy

45

ใช้ NULL NULL แสดงเจตนาของคุณ ว่ามันคือ 0 คือรายละเอียดการใช้งานที่ไม่สำคัญ


28
0 ไม่ใช่รายละเอียดการใช้งาน มาตรฐานกำหนด 0 เป็นรูปแบบบิตใดก็ตามที่แสดงถึงตัวชี้ null
Ferruccio

5
เหมือนกับ ..!! เพื่อน C ++ เป็นภาษาระดับต่ำ! ใช้ 0 มันเป็นสำนวนที่รู้จักกันดี
hasen

8
ฉันเข้าใจว่ามันเป็นส่วนหนึ่งของมาตรฐาน มันเป็นรายละเอียดการใช้งานเท่าที่อ่านโค้ด ผู้อ่านควรคิดว่า "ตัวชี้ NULL" ไม่ใช่ "0 ซึ่งในกรณีนี้หมายถึงตัวชี้ NULL ไม่ใช่ตัวเลขที่ฉันสามารถใช้ในการคำนวณทางคณิตศาสตร์ได้"
Andy Lester

2
+1 เห็นด้วยกับแอนดี้ @Ferruccio รายละเอียดการนำไปปฏิบัติของความคิดของโปรแกรมเมอร์ไม่เหมือนกับการใช้งานคอมไพเลอร์ที่กำหนดไว้
ผู้ใช้

ถ้าคุณใช้ NULL ในรหัสธรรมดาที่ไม่มีส่วนหัวที่ซับซ้อนคุณจะพบข้อผิดพลาดของ "NULL ไม่ได้กำหนดไว้ในขอบเขตนี้" ..
ArtificiallyIntelligence

38

ฉันมักจะใช้:

  • NULL สำหรับพอยน์เตอร์
  • '\0' สำหรับตัวอักษร
  • 0.0 สำหรับลอยและคู่

ที่ 0 จะทำอะไรได้ดี มันเป็นเรื่องของเจตนาการส่งสัญญาณ ที่กล่าวว่าฉันไม่ได้เกี่ยวกับเรื่องนี้


25
ya อาจใช้ 0.0F สำหรับลอยเพื่อหลีกเลี่ยง typecast โดยนัย
EvilTeach

35

ฉันหยุดใช้ NULL เพื่อสนับสนุน 0 นานมาแล้ว (รวมถึงมาโครอื่น ๆ ส่วนใหญ่) ฉันทำสิ่งนี้ไม่เพียงเพราะฉันต้องการหลีกเลี่ยงมาโครให้มากที่สุด แต่ยังเพราะ NULL ดูเหมือนจะใช้เกินในรหัส C และ C ++ ดูเหมือนว่าจะใช้เมื่อใดก็ตามที่จำเป็นต้องมีค่า 0 ไม่ใช่เพียงเพื่อตัวชี้

ในโครงการใหม่ฉันใส่มันในส่วนหัวของโครงการ:

static const int nullptr = 0;

ตอนนี้เมื่อคอมไพเลอร์ที่เข้ากันได้ของ C ++ 0x มาถึงสิ่งที่ฉันต้องทำคือลบบรรทัดนั้นออก ประโยชน์ที่ดีของสิ่งนี้คือ Visual Studio รับรู้ nullptr เป็นคำหลักและไฮไลต์มันอย่างเหมาะสม


4
การใช้ NULL จะเป็นแบบพกพาในระยะยาว 'nullptr' จะพร้อมใช้งานสำหรับบางแพลตฟอร์มและไม่ใช่สำหรับแพลตฟอร์มอื่น โซลูชันของคุณที่นี่ต้องการให้คุณใช้ตัวประมวลผลล่วงหน้ารอบการประกาศของคุณเพื่อให้แน่ใจว่าจะมีเฉพาะเมื่อจำเป็นเท่านั้น NULL จะทำสิ่งนี้โดยอัตโนมัติ
Richard Corden

6
ฉันไม่เห็นด้วย. มันจะเป็นแบบพกพาน้อยในระยะสั้นจนกว่าคอมไพเลอร์ติดตาม ระยะยาวมันจะเป็นแบบพกพาและอาจจะอ่านง่ายขึ้น
Ferruccio

4
นอกจากนี้คุณยังสามารถ #define nullptr NULL สำหรับคอมไพเลอร์ที่ไม่ใช่ C ++ 0x ของคุณ
Anteru

20
    cerr << sizeof(0) << endl;
    cerr << sizeof(NULL) << endl;
    cerr << sizeof(void*) << endl;

    ============
    On a 64-bit gcc RHEL platform you get:
    4
    8
    8
    ================

คุณธรรมของเรื่องราว คุณควรใช้ค่า NULL เมื่อคุณติดต่อกับพอยน์เตอร์

1) มันประกาศเจตนาของคุณ (อย่าให้ฉันค้นหารหัสทั้งหมดของคุณที่พยายามคิดออกว่าตัวแปรเป็นตัวชี้หรือบางประเภทตัวเลข)

2) ในการเรียก API บางอย่างที่ต้องการอาร์กิวเมนต์ของตัวแปรพวกเขาจะใช้ NULL-pointer เพื่อระบุจุดสิ้นสุดของรายการอาร์กิวเมนต์ ในกรณีนี้การใช้ '0' แทนค่า NULL อาจทำให้เกิดปัญหาได้ บนแพลตฟอร์ม 64 บิตการโทร va_arg ต้องการตัวชี้ 64 บิต แต่คุณจะผ่านจำนวนเต็ม 32 บิตเท่านั้น ดูเหมือนว่าฉันจะพึ่ง 32 บิตอื่น ๆ ที่จะเป็นศูนย์สำหรับคุณหรือไม่ ฉันเห็นคอมไพเลอร์บางตัว (เช่น icpc ของ Intel) ที่ไม่สุภาพ - และสิ่งนี้ส่งผลให้เกิดข้อผิดพลาดรันไทม์


NULLอาจจะไม่พกพาได้และไม่ปลอดภัย อาจมีแพลตฟอร์มที่ยังคงอยู่#define NULL 0(ตามคำถามที่พบบ่อยของ Stroustrup: ฉันควรใช้ NULL หรือ 0 หรือไม่อ้างอิงโดยคำถามยอดนิยมและเป็นหนึ่งในผลการค้นหาแรก) อย่างน้อยใน C ++ ที่เก่ากว่า0มีความหมายเชิงแนวคิดพิเศษในบริบทตัวชี้ คุณไม่ควรคิดอย่างรอบคอบเกี่ยวกับบิต นอกจากนี้ทราบว่าในบริบทที่แตกต่างกันจำนวนเต็ม ( short, int, long long) " sizeof(0)" จะแตกต่างกัน ฉันคิดว่าคำตอบนี้เข้าใจผิดเล็กน้อย
FooF

(ส่วนตัวเป็นโปรแกรมเมอร์ C ในชีวิตประจำวันผมมาเยี่ยมคำถามนี้จะเข้าใจว่าทำไมคนที่ต้องการที่จะใช้NULLแทน(char *)0, (const char *)0หรือ(struct Boo *)0หรือ(void *)0หรืออะไรก็ตามที่จะแสดงออกอย่างชัดเจนความตั้งใจมากขึ้น -. โดยไม่ต้อง (ในความคิดของฉัน) ยุ่งยากเกินไป)
foof

โหวตขึ้น มันเกิดขึ้นที่คอมไพเลอร์ msvc2013 ใน 64 บิต 0 เมื่อแปลงเป็นตัวชี้ไม่รับประกันว่าจะเป็น NULL Pointer
pengMiao

16

ถ้าฉันจำได้อย่างถูกต้อง NULL มีการกำหนดแตกต่างกันในส่วนหัวที่ฉันได้ใช้ สำหรับ C มันถูกกำหนดเป็น (void *) 0 และสำหรับ C ++ มันนิยามเป็นเพียง 0

#ifndef __cplusplus
#define NULL (void*)0
#else
#define NULL 0
#endif

โดยส่วนตัวแล้วฉันยังคงใช้ค่า NULL เพื่อแทนพอยน์เตอร์พอยน์เตอร์มันทำให้ชัดเจนว่าคุณกำลังใช้ตัวชี้มากกว่าประเภทอินทิกรัล ใช่ภายในค่า NULL ยังคงเป็น 0 แต่จะไม่แสดงเช่นนั้น

นอกจากนี้ฉันไม่พึ่งพาการแปลงจำนวนเต็มอัตโนมัติเป็นค่าบูลีน แต่จะเปรียบเทียบอย่างชัดเจน

ตัวอย่างเช่นต้องการใช้:

if (pointer_value != NULL || integer_value == 0)

ค่อนข้างมากกว่า:

if (pointer_value || !integer_value)

พอจะพูดได้ว่านี้แก้ได้ทั้งหมดใน C ++ 11 ที่หนึ่งก็สามารถใช้nullptrแทนNULLและยังว่าเป็นประเภทของการnullptr_tnullptr


15

ฉันจะบอกว่าประวัติศาสตร์ได้พูดไปแล้วและผู้ที่โต้แย้งว่าการใช้ 0 (ศูนย์) นั้นผิด (รวมถึง Bjarne Stroustrup) ข้อโต้แย้งในความโปรดปรานของ 0 ส่วนใหญ่เป็นสุนทรียภาพและ "ความชอบส่วนบุคคล"

หลังจากการสร้าง C ++ 11 ด้วยประเภท nullptr ใหม่คอมไพเลอร์บางคนเริ่มบ่น (ด้วยพารามิเตอร์เริ่มต้น) เกี่ยวกับการส่ง 0 ไปยังฟังก์ชันที่มีอาร์กิวเมนต์ตัวชี้เนื่องจาก 0 ไม่ใช่ตัวชี้

หากโค้ดถูกเขียนโดยใช้ NULL การค้นหาและแทนที่แบบง่ายสามารถทำได้ผ่าน codebase เพื่อทำให้เป็น nullptr แทน หากคุณติดอยู่กับรหัสที่เขียนโดยใช้ตัวเลือก 0 เป็นตัวชี้มันน่าเบื่อกว่าที่จะอัปเดต

และถ้าคุณต้องเขียนโค้ดใหม่ตอนนี้ถึงมาตรฐาน C ++ 03 (และไม่สามารถใช้ nullptr) ได้คุณควรใช้ NULL มันจะทำให้คุณอัปเดตได้ง่ายขึ้นในอนาคต


11

ฉันมักจะใช้ 0 ฉันไม่ชอบมาโครและไม่มีการรับประกันว่าส่วนหัวของบุคคลที่สามที่คุณใช้ไม่ได้กำหนด NULL ให้เป็นสิ่งที่แปลก

คุณสามารถใช้วัตถุ nullptr ตามที่เสนอโดย Scott Meyers และอื่น ๆ จนกว่า C ++ จะได้รับคำหลัก nullptr:

const // It is a const object...
class nullptr_t 
{
public:
    template<class T>
    operator T*() const // convertible to any type of null non-member pointer...
    { return 0; }

    template<class C, class T>
    operator T C::*() const   // or any type of null member pointer...
    { return 0; }

private:
    void operator&() const;  // Can't take address of nullptr

} nullptr = {};

Google "nullptr" สำหรับข้อมูลเพิ่มเติม


9
ไลบรารีบุคคลที่สามใด ๆ ที่กำหนดค่า NULL ให้กับสิ่งอื่นที่ไม่ใช่ 0 (หรือ(void*)0หากถูกคอมไพล์เป็นรหัส C) เพียงแค่ถามถึงปัญหาและไม่ควรใช้
Adam Rosenfield

2
คุณเคยเห็นห้องสมุดที่นิยาม NULL ใหม่หรือไม่? เคย? หากห้องสมุดดังกล่าวเคยมีอยู่คุณจะมีปัญหาใหญ่กว่า NULL ที่นิยามใหม่เช่นคุณกำลังใช้ห้องสมุดที่โง่พอที่จะกำหนด NULL ใหม่
Andy Lester

1
กว่าทศวรรษที่แล้วฉันจำไม่ได้ว่าต้องจัดการกับส่วนหัวของบุคคลที่สามบางอย่างอาจเป็น Orbix หรือ ObjectStore ที่กำหนด NULL ฉันคิดว่าฉันมีความเกลียดชังทางพยาธิวิทยาของมาโครหลังจากเสียเวลาหลายวันหลายคืนในการพยายามให้ส่วนหัวของบุคคลที่สามทำงานกับ windows.h ได้
jon-hanson

2
"ไม่ชอบมาโคร" เป็นคำวิจารณ์แปลก ๆ ของ #define ที่เหมือนวัตถุ บางทีคุณอาจจะพูดว่าคุณไม่ชอบ C-preprocessor?
Andrew Prock

@Andrew - ผลประโยชน์เพียงอย่างเดียวของNULLมากกว่า(type *)0คือ searchability มันดูเหมือนว่าฉัน มิฉะนั้นดูเหมือนว่าจะทำให้เสียความรู้สึกที่ไม่จำเป็นถ้ามันไม่ใช่สำนวน C โดยส่วนตัวผมคิดว่าสำนวนที่แพร่กระจายNULLไปทั่วสถานที่นั้นสมควรที่จะตาย NULLมาโครไร้ประโยชน์ในความคิดของฉัน ใบมีดโกนของ Occam มีงานต้องทำที่นี่ ...
FooF

11

ฉันเคยทำงานกับเครื่องที่ 0 เป็นที่อยู่ที่ถูกต้องและ NULL ถูกกำหนดเป็นค่าฐานแปดพิเศษ บนเครื่องนั้น (0! = NULL) ดังนั้นรหัสเช่น

char *p;

...

if (p) { ... }

จะไม่ทำงานตามที่คุณคาดหวัง คุณต้องเขียน

if (p != NULL) { ... }

แม้ว่าฉันจะเชื่อว่าคอมไพเลอร์ส่วนใหญ่กำหนด NULL เป็น 0 วันนี้ฉันยังจำบทเรียนจากปีที่ผ่านมา: NULL ไม่จำเป็นต้องเป็น 0


26
คุณไม่ได้ใช้คอมไพเลอร์ที่เข้ากันได้ มาตรฐานบอกว่า NULL คือ 0 และคอมไพเลอร์ควรแปลง 0 ในบริบทตัวชี้เป็นค่า NULL จริงที่เหมาะสมสำหรับส่วนโค้ง
Evan Teran

17
ใช่คุณถูก. นี่เป็นช่วงกลางปี ​​80 ก่อนที่ ANSI จะสร้างมาตรฐาน C ไม่มีสิ่งนั้นเป็นความสอดคล้องและผู้เขียนคอมไพเลอร์มีอิสระในการตีความภาษาที่พวกเขาเห็นว่าเหมาะสม นั่นเป็นเหตุผลว่าทำไมมาตรฐานจึงจำเป็น
mxg

9

ฉันคิดว่ามาตรฐานรับรองว่า NULL == 0 ดังนั้นคุณสามารถทำได้ ฉันชอบ NULL เพราะเอกสารแสดงเจตจำนงของคุณ


ถ้าคุณมีโครงสร้างที่ซ้อนกันผมคิดว่าการพูดว่าเป็นการแสดงออกถึงความตั้งใจที่ชัดเจนมากขึ้นกว่าfoo.bar_ptr = (Bar *) 0 foo.bar_ptr = NULLนิสัยนี้ยังช่วยให้คอมไพเลอร์ตรวจจับข้อผิดพลาดที่เข้าใจผิดสำหรับคุณ สำหรับฉันfoo.bar_ptr = 0แสดงความตั้งใจเช่นเดียวกับการใช้NULLถ้าฉันรู้ว่าfoo.bar_ptrมันเป็นตัวชี้
FooF

9

การใช้ 0 หรือ NULL จะมีผลเหมือนกัน

อย่างไรก็ตามนั่นไม่ได้หมายความว่าพวกเขาทั้งสองเป็นแนวปฏิบัติที่ดี เนื่องจากไม่มีประสิทธิภาพที่แตกต่างกันการเลือกตัวเลือกที่มีความตระหนักในระดับต่ำกว่าทางเลือกผู้ไม่เชื่อเรื่องพระเจ้า / นามธรรมเป็นวิธีปฏิบัติที่ไม่ดีในการเขียนโปรแกรม ช่วยให้ผู้อ่านของรหัสของคุณเข้าใจกระบวนการคิดของคุณ

NULL, 0, 0.0, '\ 0', 0x00 และ whatelse ทั้งหมดแปลเป็นสิ่งเดียวกัน แต่เป็นเอนทิตีเชิงตรรกะที่แตกต่างกันในโปรแกรมของคุณ พวกเขาควรจะใช้เช่นนี้ NULL คือตัวชี้, 0 คือปริมาณ, 0x0 เป็นค่าที่บิตน่าสนใจ ฯลฯ คุณจะไม่กำหนด '\ 0' ให้กับตัวชี้ไม่ว่าจะเป็นการรวบรวมหรือไม่

ฉันรู้ว่าบางชุมชนส่งเสริมให้แสดงความรู้ในเชิงลึกของสภาพแวดล้อมโดยการทำลายสัญญาของสภาพแวดล้อม อย่างไรก็ตามโปรแกรมเมอร์ผู้รับผิดชอบทำรหัสที่สามารถบำรุงรักษาได้และป้องกันไม่ให้มีการใช้รหัสดังกล่าว


5

แปลกไม่มีใครรวมถึง Stroustroup กล่าวว่า ในขณะที่พูดมากเกี่ยวกับมาตรฐานและความงามไม่มีใครสังเกตเห็นว่ามันเป็นอันตรายที่จะใช้0ในการNULL's sizeof(int) != sizeof(void*)แทนตัวอย่างเช่นในรายการอาร์กิวเมนต์ตัวแปรกับสถาปัตยกรรมที่ เช่นเดียวกับ Stroustroup ฉันชอบ0เหตุผลด้านสุนทรียภาพ แต่ต้องระวังไม่ให้ใช้เพราะมันอาจจะคลุมเครือ


และในสถานที่อันตรายที่คุณยังสามารถใช้0บริการที่มีให้คุณระบุว่า0คุณหมายถึง - ตัวอย่างเช่น(int *)0, (char *)0, (const char *)0หรือ(void *)0หรือ(unsigned long long) 0หรืออะไรก็ตาม NULLนี้ในความคิดของฉันเป็นการแสดงออกถึงความตั้งใจที่ชัดเจนมากขึ้นกว่า
FooF

1
แน่นอนว่าถ้าคุณไม่รู้ว่าNULLหมายถึงอะไร
Michael Krelin - แฮ็กเกอร์

โดยส่วนตัวแล้วฉันรู้สึกว่ามันน่ารังเกียจนิดหน่อยที่จะต้องใช้บางสิ่งบางอย่างโดยไม่จำเป็น(void *)เมื่อฉันสามารถใช้ประเภทที่แน่นอนได้ ฉันตั้งใจให้ตัวอย่าง (โดยทั่วไป) จำนวนเต็ม 64- บิตในรายการเพราะมันคล้ายกับกรณีของตัวชี้ นอกจากนี้หากความทรงจำของฉันที่ C ++ เก่ากำหนดไว้NULLว่า0มีความถูกต้อง (เป็นปีนับตั้งแต่ที่ฉันได้เขียนโปรแกรมใน C ++) แล้วเราไม่เห็นการปรับปรุงในความถูกต้องของโปรแกรม มาตรฐานใหม่ C ++ โชคดีที่ให้ nullptrคำหลักเพื่อให้เราสามารถกำจัดความNULLอัปลักษณ์นี้และความขัดแย้งทั้งหมดเมื่อเขียน C ++ ที่ใหม่กว่า
FooF

นั่นเป็นเหตุผลว่าทำไมการคัดเลือกให้(void*)ได้รับการสรุปออกNULLมา และNULLจริง ๆ แล้วเป็นการแสดงเจตนาค่อนข้างชัดเจนตลอดเวลา และฉันคิดว่าความทรงจำของคุณผิด ไม่แน่ใจเกี่ยวกับมาตรฐาน แต่ในทางปฏิบัติฉันเชื่อว่าเป็น(void*)0ไปได้ และ yess nullptrเป็นตัวเลือกที่ดีแม้ว่ามันจะมีจำนวนเท่ากันNULL- การระบุ null-pointer โดยไม่ระบุประเภท
Michael Krelin - แฮ็กเกอร์

1
@FooF บนบางแพลตฟอร์ม - อาจจะ ในความเป็นจริงของฉันมันทำงานได้และดังนั้นฉันสงสัยว่ามันถูกกำหนดเป็นตัวชี้ สำหรับความแข็งแกร่งใช่สิ่งที่ฉันพยายามพูดว่าการใช้nullptrหมีมีข้อความเช่นNULLเดียวกับที่เกี่ยวกับการแสดงเจตนาที่คุณกล่าวถึงในการเริ่มต้นเท่านั้น (การประมวลผลล่วงหน้าNULLกับgccผลตอบแทนที่ทันสมัย__nullไม่ว่าจะเป็นอะไรก็ตาม)
Michael Krelin - แฮกเกอร์

4

ฉันพยายามหลีกเลี่ยงคำถามทั้งหมดโดยใช้การอ้างอิง C ++ หากเป็นไปได้ ค่อนข้างมากกว่า

void foo(const Bar* pBar) { ... }

คุณมักจะสามารถเขียน

void foo(const Bar& bar) { ... }

แน่นอนว่ามันไม่ได้ผลเสมอไป แต่พอยน์เตอร์พอยน์เตอร์สามารถใช้มากเกินไปได้


3

ฉันใช้ Stroustrup กับอันนี้ :-) เนื่องจาก NULL ไม่ได้เป็นส่วนหนึ่งของภาษาฉันชอบที่จะใช้ 0


3

ส่วนใหญ่การตั้งค่าส่วนตัวแม้ว่าหนึ่งสามารถทำให้อาร์กิวเมนต์ที่ NULL ทำให้มันค่อนข้างชัดเจนว่าวัตถุเป็นตัวชี้ซึ่งปัจจุบันไม่ได้ชี้ไปที่อะไรเช่น

void *ptr = &something;
/* lots o' code */
ptr = NULL; // more obvious that it's a pointer and not being used

IIRC มาตรฐานไม่จำเป็นต้องมีค่า NULL เป็น 0 ดังนั้นการใช้อะไรก็ตามที่กำหนดไว้ใน <stddef.h> น่าจะดีที่สุดสำหรับคอมไพเลอร์ของคุณ

อีกแง่มุมหนึ่งของการโต้แย้งคือคุณควรใช้การเปรียบเทียบแบบลอจิคัล (การบอกเป็นนัยถึงการบูล) หรือการตรวจสอบอย่างชัดเจนกับ NULL แต่นั่นก็เป็นเรื่องที่อ่านง่ายเช่นกัน


3

ฉันชอบใช้ NULL เพราะมันชัดเจนว่าเจตนาของคุณคือค่าที่แสดงถึงตัวชี้ไม่ใช่ค่าเลขคณิต ความจริงที่ว่ามันเป็นมาโครนั้นโชคร้าย แต่เนื่องจากมันฝังแน่นอย่างกว้างขวางจึงมีอันตรายเล็กน้อย (เว้นแต่มีบางคนทำบางสิ่งที่ปวดหัว) ฉันหวังว่ามันจะเป็นคำหลักตั้งแต่ต้น แต่คุณจะทำอะไรได้บ้าง

ที่กล่าวว่าฉันไม่มีปัญหากับการใช้พอยน์เตอร์เป็นค่าความจริงในตัวเอง เช่นเดียวกับ NULL มันเป็นสำนวนที่ฝังแน่น

C ++ 09 จะเพิ่มโครงสร้าง nullptr ซึ่งฉันคิดว่าค้างชำระนานเกินไป


1

ฉันมักจะใช้ 0 ไม่ได้เพราะเหตุผลที่คิดออกจริง ๆ เพียงเพราะเมื่อฉันเรียนรู้ C ++ ครั้งแรกฉันอ่านสิ่งที่แนะนำโดยใช้ 0 และฉันก็ทำอย่างนั้นเสมอ ในทางทฤษฎีอาจมีปัญหาความสับสนในการอ่าน แต่ในทางปฏิบัติฉันไม่เคยเจอปัญหาดังกล่าวในชั่วโมงการทำงานหลายพันชั่วโมงและหลายล้านบรรทัดของรหัส ดังที่สเตราสตรูปบอกว่ามันเป็นเรื่องของสุนทรียศาสตร์ส่วนตัวจนกระทั่งมาตรฐานกลายเป็นโมฆะ


1

มีคนบอกฉันอีกครั้ง ... ฉันจะกำหนด NULL เป็น 69 อีกครั้งตั้งแต่นั้นมาฉันไม่ได้ใช้: P

ทำให้รหัสของคุณค่อนข้างเสี่ยง

แก้ไข:

ไม่ใช่ทุกอย่างในมาตรฐานที่สมบูรณ์แบบ แมโคร NULL เป็นค่าคงที่ตัวชี้ C ++ null ที่ใช้งานซึ่งไม่สามารถทำงานร่วมกับมาโคร C NULL ได้อย่างสมบูรณ์สิ่งที่นอกเหนือจากชนิดการซ่อนการแปลงโดยนัยในเครื่องมือที่ไร้ประโยชน์และมีแนวโน้มที่จะเกิดข้อผิดพลาด

NULL ไม่ทำงานเป็นตัวชี้โมฆะ แต่เป็น O / OL ตัวอักษร

บอกฉันตัวอย่างต่อไปไม่สับสน:

void foo(char *); 
void foo(int); 
foo(NULL); // calls int version instead of pointer version! 

เป็นเพราะทั้งหมดนั้นในมาตรฐานใหม่จะปรากฏ std :: nullptr_t

หากคุณไม่ต้องการรอมาตรฐานใหม่และต้องการใช้ nullptr ให้ใช้อย่างน้อยหนึ่งค่าที่ดีเช่นเดียวกับข้อเสนอของ Meyers (ดูความคิดเห็น jon.h)


5
NULLเป็นส่วนที่กำหนดไว้อย่างดีของมาตรฐาน C ++ การให้ผู้ที่ต้องการกำหนดรหัสมาโครมาตรฐานใหม่ในโครงการของคุณทำให้โค้ดของคุณ 'มีความเสี่ยง'; การใช้NULLไม่ได้
CB Bailey

1

ฉันเถียงไม่ได้ใช้ 0 หรือตัวชี้ NULL เลยเมื่อใดก็ตามที่เป็นไปได้

การใช้พวกมันจะนำไปสู่ความผิดพลาดในการแบ่งกลุ่มในรหัสของคุณ จากประสบการณ์ของฉันสิ่งนี้และพอยน์เตอร์ใน gereral เป็นหนึ่งในแหล่งใหญ่ที่สุดของข้อบกพร่องใน C ++

นอกจากนี้ยังนำไปสู่คำสั่ง "if-not-null" ทั่วรหัสของคุณ ถ้าคุณสามารถใช้สถานะที่ถูกต้องได้ดีกว่าเสมอ

มีทางเลือกที่ดีกว่าเกือบตลอดเวลา


2
ความผิดพลาดการแบ่งส่วนการรับประกัน (และก็มีการรับประกันในระบบที่ทันสมัยเมื่อคุณ dereference 0) เป็นประโยชน์สำหรับการแก้จุดบกพร่อง ดีกว่าการทิ้งขยะแบบสุ่มลงไปและทำให้ใครรู้ว่าผลลัพธ์คืออะไร
การแข่งขัน Lightness ใน Orbit

-4

การตั้งตัวชี้ไปที่ 0 นั้นไม่ชัดเจนเลย โดยเฉพาะอย่างยิ่งถ้าคุณมาภาษาอื่นที่ไม่ใช่ C ++ ซึ่งรวมถึง C และ Javascript

ฉันเพิ่งจะลบรหัสบางอย่างเช่น:

virtual void DrawTo(BITMAP *buffer) =0;

สำหรับฟังก์ชั่นเสมือนบริสุทธิ์เป็นครั้งแรก ฉันคิดว่ามันจะเป็น jiberjash เวทมนตร์เป็นเวลาหนึ่งสัปดาห์ เมื่อฉันรู้ว่ามันเป็นเพียงการตั้งค่าตัวชี้ฟังก์ชั่นเป็นnull(เพราะฟังก์ชั่นเสมือนเป็นเพียงตัวชี้ฟังก์ชั่นในกรณีส่วนใหญ่สำหรับ C ++) ฉันเตะตัวเอง

virtual void DrawTo(BITMAP *buffer) =null;

จะมีความสับสนน้อยกว่า basterdation ที่ไม่มีระยะห่างที่เหมาะสมกับดวงตาใหม่ของฉัน อันที่จริงฉันสงสัยว่าทำไม C ++ ไม่ใช้ตัวพิมพ์เล็กnullเหมือนมันใช้ตัวพิมพ์เล็กเท็จและจริงตอนนี้


โดยทั่วไปฉันชอบ NULL ถึง 0 สำหรับตัวชี้ อย่างไรก็ตาม '= 0;' เป็นวิธีที่ใช้สำนวนการประกาศฟังก์ชั่นเสมือนจริงใน C ++ ฉันขอแนะนำอย่างยิ่งให้คุณไม่ใช้ '= NULL;' สำหรับกรณีนี้โดยเฉพาะ
danio

นี่คือความคิดเห็นที่ตลกที่สุดใน StackOverflow คุณอาจรู้อยู่แล้วว่าตัวอย่างที่คุณให้ไว้เป็นไวยากรณ์สำหรับฟังก์ชันเสมือนจริงไม่ใช่เป็นตัวชี้ และใช่ @danio ถูกต้องคุณไม่ควรใช้ NULL สำหรับฟังก์ชั่นเสมือนจริง
sgowd
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.