เหตุใดพอยน์เตอร์จึงไม่เริ่มต้นด้วย NULL ตามค่าเริ่มต้น


118

ใครช่วยอธิบายได้NULLไหมว่าทำไมพอยน์เตอร์ถึงไม่เริ่มต้น
ตัวอย่าง:

  void test(){
     char *buf;
     if (!buf)
        // whatever
  }

โปรแกรมจะไม่เข้าไปใน if เพราะbufไม่ใช่โมฆะ

ฉันต้องการทราบว่าเหตุใดเราจึงต้องมีตัวแปรที่มีถังขยะอยู่ในกรณีใดตัวชี้พิเศษที่ระบุถึงถังขยะในหน่วยความจำ


13
เนื่องจากประเภทพื้นฐานถูกทิ้งไว้โดยไม่ได้เริ่มต้น ดังนั้นฉันถือว่าคำถาม "จริง" ของคุณคือทำไมประเภทพื้นฐานจึงไม่เริ่มต้น?
GManNickG

11
"โปรแกรมจะไม่เข้าไปใน if เพราะ buf ไม่เป็นโมฆะ" ไม่ถูกต้อง เนื่องจากคุณไม่รู้ว่า buf คืออะไรคุณจึงไม่สามารถรู้ได้ว่ามันไม่ใช่อะไร
Drew Dormann

ตรงกันข้ามกับบางอย่างเช่น Java, C ++ ให้ความรับผิดชอบแก่นักพัฒนามากขึ้น
Rishi

จำนวนเต็มตัวชี้ค่าเริ่มต้นเป็น 0 ถ้าคุณใช้ () ตัวสร้าง
Erik Aronesty

เนื่องจากสมมติฐานที่ว่าคนที่ใช้ C ++ รู้ว่าพวกเขากำลังทำอะไรอยู่ยิ่งไปกว่านั้นคนที่ใช้ตัวชี้ดิบเหนือตัวชี้อัจฉริยะจะรู้ (ยิ่งกว่านั้น) ว่าพวกเขากำลังทำอะไร!
Lofty Lion

คำตอบ:


161

เราทุกคนตระหนักดีว่าควรเริ่มต้นตัวชี้ (และประเภท POD อื่น ๆ )
คำถามจะกลายเป็น "ใครควรเริ่มต้น"

โดยทั่วไปมีสองวิธี:

  • คอมไพเลอร์เริ่มต้นใช้งาน
  • นักพัฒนาเริ่มต้นใช้งาน

สมมติว่าคอมไพเลอร์เริ่มต้นตัวแปรใด ๆ ที่นักพัฒนาไม่ได้เริ่มต้นอย่างชัดเจน จากนั้นเราก็พบกับสถานการณ์ที่การเริ่มต้นตัวแปรนั้นไม่สำคัญและเหตุผลที่นักพัฒนาไม่ดำเนินการที่จุดประกาศคือเขา / เธอจำเป็นต้องดำเนินการบางอย่างจากนั้นจึงมอบหมาย

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

ไม่ใช่แค่เรื่องเวลา แต่ยังมีพื้นที่ มีสภาพแวดล้อมมากมายที่ทรัพยากรทั้งสองอยู่ในระดับพรีเมี่ยมและนักพัฒนาไม่ต้องการที่จะยอมแพ้เช่นกัน

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


5
Bob Tabor กล่าวว่า "มีคนจำนวนมากไม่ได้ให้ความคิดในการเริ่มต้นมากพอ!" มัน 'เป็นมิตร' ในการเริ่มต้นตัวแปรทั้งหมดโดยอัตโนมัติ แต่ต้องใช้เวลาและโปรแกรมที่ช้าก็ 'ไม่เป็นมิตร' สเปรดชีตหรือบรรณาธิการที่แสดงให้เห็นว่าขยะมูลฝอยแบบสุ่มที่พบนั้นไม่สามารถยอมรับได้ C ซึ่งเป็นเครื่องมือที่เฉียบคมสำหรับผู้ใช้ที่ได้รับการฝึกฝน (เป็นอันตรายหากใช้ในทางที่ผิด) ไม่ควรใช้เวลาในการเริ่มต้นตัวแปรอัตโนมัติ มาโครวงล้อการฝึกอบรมเพื่อเริ่มตัวแปรอาจเป็นได้ แต่หลายคนคิดว่าดีกว่าที่จะยืนขึ้นมีสติและมีเลือดออกเล็กน้อย คุณทำงานในแบบที่คุณฝึกฝนในเวลาไม่นาน ดังนั้นจงฝึกฝนอย่างที่คุณเป็น
Bill IV

2
คุณจะแปลกใจว่ามีกี่จุดที่จะหลีกเลี่ยงได้เพียงแค่มีคนแก้ไขการเริ่มต้นทั้งหมด นี่จะเป็นงานที่น่าเบื่อหากไม่ใช่คำเตือนของคอมไพเลอร์
Jonathan Henson

4
@ โลกิฉันมีช่วงเวลาที่ยากลำบากตามประเด็นของคุณ ฉันแค่พยายามยกย่องคำตอบของคุณว่าเป็นประโยชน์ฉันหวังว่าคุณจะรวบรวมได้ ถ้าไม่ใช่ฉันขอโทษ
Jonathan Henson

3
ถ้าตัวชี้ถูกตั้งค่าเป็น NULL ก่อนจากนั้นตั้งค่าเป็นค่าใดก็ได้คอมไพลเลอร์ควรจะตรวจจับสิ่งนี้ได้และปรับการเริ่มต้น NULL ครั้งแรกให้เหมาะสมใช่ไหม
Korchkidu

1
@Korchkidu: บางครั้ง. ปัญหาสำคัญประการหนึ่งคือไม่มีทางที่จะเตือนคุณว่าคุณลืมเริ่มต้นเนื่องจากไม่สามารถทราบได้ว่าค่าเริ่มต้นไม่เหมาะสำหรับการใช้งานของคุณ
Deduplicator

41

การอ้างอิง Bjarne Stroustrup ใน TC ++ PL (Special Edition น. 22):

การใช้งานคุณลักษณะไม่ควรกำหนดค่าใช้จ่ายที่สำคัญในโปรแกรมที่ไม่จำเป็นต้องใช้


และอย่าให้ตัวเลือกด้วย ดูเหมือนว่า
โจนาธาน

8
@ โจนาธานไม่มีอะไรป้องกันไม่ให้คุณเริ่มต้นตัวชี้เป็นโมฆะ - หรือเป็น 0 ตามมาตรฐานใน C ++
stefanB

8
ใช่ แต่ Stroustrup สามารถทำให้ความถูกต้องของโปรแกรมสนับสนุนไวยากรณ์เริ่มต้นมากกว่าประสิทธิภาพโดยการกำหนดค่าเริ่มต้นของตัวชี้เป็นศูนย์และทำให้โปรแกรมเมอร์ต้องร้องขอให้ตัวชี้ไม่ได้กำหนดค่าเริ่มต้นอย่างชัดเจน ท้ายที่สุดแล้วคนส่วนใหญ่ชอบที่ถูกต้อง แต่ช้ามากกว่าเร็ว แต่ผิดเนื่องจากโดยทั่วไปแล้วการเพิ่มประสิทธิภาพโค้ดจำนวนเล็กน้อยนั้นง่ายกว่าการแก้ไขข้อบกพร่องในโปรแกรมทั้งหมด โดยเฉพาะอย่างยิ่งเมื่อคอมไพเลอร์ที่ดีสามารถทำได้มาก
Robert Tuck

1
มันไม่ทำลายความเข้ากันได้ แนวคิดนี้ได้รับการพิจารณาร่วมกับ "int * x = __uninitialized" โดยค่าเริ่มต้นคือความเร็วตามเจตนา
MSalters

4
ผมชอบสิ่งที่Dไม่ หากคุณไม่ต้องการเริ่มต้นใช้ไวยากรณ์นี้float f = void;หรือint* ptr = void;. ตอนนี้เริ่มต้นแล้วโดยค่าเริ่มต้น แต่ถ้าคุณต้องการจริงๆคุณสามารถหยุดคอมไพเลอร์ไม่ให้ทำ
deft_code

23

เนื่องจากการเริ่มต้นต้องใช้เวลา และใน C ++ สิ่งแรกที่คุณควรทำกับตัวแปรใด ๆ คือการเริ่มต้นอย่างชัดเจน:

int * p = & some_int;

หรือ:

int * p = 0;

หรือ:

class A {
   public:
     A() : p( 0 ) {}  // initialise via constructor
   private:
     int * p;
};

1
k ถ้าการเริ่มต้นต้องใช้เวลาและฉันยังต้องการอยู่จะทำให้พอยน์เตอร์ของฉันเป็นโมฆะโดยไม่ต้องตั้งค่าด้วยตนเองได้หรือไม่? ดูไม่ใช่เพราะฉันไม่ต้องการที่จะถูกต้องเพราะฉันดูเหมือนว่าฉันจะไม่เคยใช้พอยน์เตอร์ที่เป็นหน่วยกับถังขยะในที่อยู่ของพวกเขา
โจนาธาน

1
คุณเริ่มต้นสมาชิกคลาสในตัวสร้างของคลาสนั่นคือวิธีการทำงานของ C ++

3
@ โจนาธาน: แต่โมฆะก็เป็นขยะเช่นกัน คุณไม่สามารถทำอะไรที่เป็นประโยชน์ด้วยตัวชี้ว่างได้ การอ้างอิงเป็นเพียงข้อผิดพลาด สร้างพอยน์เตอร์ด้วยค่าที่เหมาะสมไม่ใช่ค่าว่าง
DrPizza

2
การเริ่มต้น apointer เป็น Nnull อาจเป็นสิ่งที่ต้องทำและมีการดำเนินการหลายอย่างที่คุณสามารถดำเนินการกับพอยน์เตอร์ว่าง - คุณสามารถทดสอบและเรียกลบได้

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

20

เนื่องจากหนึ่งในคำขวัญของ C ++ คือ:


คุณไม่ต้องจ่ายสำหรับสิ่งที่คุณไม่ได้ใช้


ด้วยเหตุผลอย่างนี้operator[]ของvectorชั้นไม่ได้ตรวจสอบถ้าดัชนีอยู่นอกขอบเขตเช่น


12

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


ฉันเดาว่าเนื่องจาก C ถือเป็นภาษาระดับล่างที่เข้าถึงหน่วยความจำได้ง่าย (หรือที่เรียกว่าพอยน์เตอร์) ดังนั้นจึงให้อิสระในการทำสิ่งที่คุณต้องการและไม่กำหนดค่าใช้จ่ายโดยการเริ่มต้นทุกอย่าง BTW ฉันคิดว่ามันขึ้นอยู่กับแพลตฟอร์มเพราะฉันทำงานบนแพลตฟอร์มมือถือที่ใช้ linux ซึ่งเริ่มต้นหน่วยความจำทั้งหมดเป็น 0 ก่อนใช้งานดังนั้นตัวแปรทั้งหมดจะถูกตั้งค่าเป็น 0
stefanB

8

นอกจากนี้เรายังมีคำเตือนเมื่อคุณระเบิด: "อาจใช้ก่อนกำหนดค่า" หรือ verbage ที่คล้ายกันขึ้นอยู่กับคอมไพเลอร์ของคุณ

คุณรวบรวมคำเตือนใช่ไหม?


และเป็นไปได้ว่าเป็นเพียงการรับรู้ว่าการติดตามคอมไพเลอร์อาจผิดพลาด
Deduplicator

6

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

C ++ ไม่ใช่ C89 นรกแม้แต่ C ก็ไม่ใช่ C89 คุณสามารถผสมการประกาศและรหัสได้ดังนั้นคุณควรเลื่อนการประกาศออกไปจนกว่าคุณจะมีค่าที่เหมาะสมในการเริ่มต้น


2
จากนั้นทุกค่าจะต้องถูกเขียนถึงสองครั้ง - หนึ่งครั้งโดยรูทีนการตั้งค่าของคอมไพเลอร์และอีกครั้งโดยโปรแกรมของผู้ใช้ ไม่ใช่ปัญหาใหญ่ แต่จะเพิ่มขึ้น (เช่นถ้าคุณสร้างอาร์เรย์ 1 ล้านรายการ) หากคุณต้องการเริ่มต้นอัตโนมัติคุณสามารถสร้างประเภทของคุณเองได้ตลอดเวลา แต่วิธีนี้คุณจะไม่ถูกบังคับให้ยอมรับค่าใช้จ่ายที่ไม่จำเป็นหากคุณไม่ต้องการ
Jeremy Friesner

3

ตัวชี้เป็นเพียงอีกประเภทหนึ่ง ถ้าคุณสร้างint, charหรือพิมพ์ POD อื่น ๆ มันไม่ได้เริ่มต้นใช้ให้เป็นศูนย์ดังนั้นจึงควรจะเป็นตัวชี้? สิ่งนี้อาจถือได้ว่าเป็นค่าใช้จ่ายที่ไม่จำเป็นสำหรับผู้ที่เขียนโปรแกรมเช่นนี้

char* pBuf;
if (condition)
{
    pBuf = new char[50];
}
else
{
    pBuf = m_myMember->buf();
}

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


1
ในทางกลับกันคุณสามารถทำ char * pBuf = condition? ถ่านใหม่ [50]: m_myMember-> buf (); มันเหมือนกับเรื่องของไวยากรณ์มากกว่าประสิทธิภาพ แต่ฉันก็ยังเห็นด้วยกับคุณ
the_drow

1
@the_drow: เราสามารถทำให้ซับซ้อนมากขึ้นได้ดังนั้นจึงไม่สามารถเขียนใหม่ได้
Deduplicator

2

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

template<typename T> class InitializedPointer
{
public:
    typedef T       TObj;
    typedef TObj    *PObj;
protected:
    PObj        m_pPointer;

public:
    // Constructors / Destructor
    inline InitializedPointer() { m_pPointer=0; }
    inline InitializedPointer(PObj InPointer) { m_pPointer = InPointer; }
    inline InitializedPointer(const InitializedPointer& oCopy)
    { m_pPointer = oCopy.m_pPointer; }
    inline ~InitializedPointer() { m_pPointer=0; }

    inline PObj GetPointer() const  { return (m_pPointer); }
    inline void SetPointer(PObj InPtr)  { m_pPointer = InPtr; }

    // Operator Overloads
    inline InitializedPointer& operator = (PObj InPtr)
    { SetPointer(InPtr); return(*this); }
    inline InitializedPointer& operator = (const InitializedPointer& InPtr)
    { SetPointer(InPtr.m_pPointer); return(*this); }
    inline PObj operator ->() const { return (m_pPointer); }
    inline TObj &operator *() const { return (*m_pPointer); }

    inline bool operator!=(PObj pOther) const
    { return(m_pPointer!=pOther); }
    inline bool operator==(PObj pOther) const
    { return(m_pPointer==pOther); }
    inline bool operator!=(const InitializedPointer& InPtr) const
    { return(m_pPointer!=InPtr.m_pPointer); }
    inline bool operator==(const InitializedPointer& InPtr) const
    { return(m_pPointer==InPtr.m_pPointer); }

    inline bool operator<=(PObj pOther) const
    { return(m_pPointer<=pOther); }
    inline bool operator>=(PObj pOther) const
    { return(m_pPointer>=pOther); }
    inline bool operator<=(const InitializedPointer& InPtr) const
    { return(m_pPointer<=InPtr.m_pPointer); }
    inline bool operator>=(const InitializedPointer& InPtr) const
    { return(m_pPointer>=InPtr.m_pPointer); }

    inline bool operator<(PObj pOther) const
    { return(m_pPointer<pOther); }
    inline bool operator>(PObj pOther) const
    { return(m_pPointer>pOther); }
    inline bool operator<(const InitializedPointer& InPtr) const
    { return(m_pPointer<InPtr.m_pPointer); }
    inline bool operator>(const InitializedPointer& InPtr) const
    { return(m_pPointer>InPtr.m_pPointer); }
};

1
หากฉันใช้สิ่งนี้ฉันจะไม่กังวลกับ te copy ctor หรือ op มอบหมาย - ค่าเริ่มต้นค่อนข้างโอเค และผู้ทำลายล้างของคุณไม่มีจุดหมาย คุณสามารถทดสอบพอยน์เตอร์ได้โดยใช้น้อยกว่าตัวดำเนินการและทั้งหมด) ในบางสถานการณ์) ดังนั้นคุณควรระบุ

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

ตกลงเพิ่มตัวดำเนินการเปรียบเทียบทั้งหมด การแทนที่เริ่มต้นอาจซ้ำซ้อน แต่อยู่ที่นี่อย่างชัดเจนเนื่องจากเป็นตัวอย่าง
อดิศักดิ์

1
ฉันไม่เข้าใจว่าสิ่งนี้จะทำให้พอยน์เตอร์ทั้งหมดเป็นโมฆะได้อย่างไรโดยไม่ต้องตั้งค่าด้วยตนเองคุณช่วยอธิบายสิ่งที่คุณทำที่นี่ได้อย่างไร
Jonathan

1
@ โจนาธาน: โดยพื้นฐานแล้วนี่คือ "ตัวชี้อัจฉริยะ" ที่ไม่ทำอะไรเลยนอกจากตั้งค่าตัวชี้เป็นโมฆะ IE แทนคุณFoo *aใช้InitializedPointer<Foo> a- การออกกำลังกายเชิงวิชาการอย่างFoo *a=0แท้จริงเช่นเดียวกับการพิมพ์น้อย อย่างไรก็ตามโค้ดด้านบนมีประโยชน์มากจากมุมมองทางการศึกษา ด้วยการปรับเปลี่ยนเพียงเล็กน้อย (ไปยัง ctor / dtor "และตัวเลือกการกำหนด) สามารถขยายไปยังสมาร์ทพอยน์เตอร์ประเภทต่างๆได้อย่างง่ายดายรวมถึงพอยน์เตอร์ที่กำหนดขอบเขต (ซึ่งไม่มีค่าตัวทำลาย) และตัวชี้ที่นับการอ้างอิงโดยการเพิ่ม inc / ตัดสินใจดำเนินการเมื่อตั้งค่าหรือล้าง m_pPointer
อดิศักดิ์

2

โปรดทราบว่าข้อมูลคงที่เริ่มต้นเป็น 0 (เว้นแต่คุณจะพูดเป็นอย่างอื่น)

และใช่คุณควรประกาศตัวแปรของคุณให้ช้าที่สุดเท่าที่จะเป็นไปได้และด้วยค่าเริ่มต้น รหัสเช่น

int j;
char *foo;

ควรปิดเสียงระฆังปลุกเมื่อคุณอ่าน ฉันไม่รู้ว่าผ้าสำลีใด ๆสามารถชักชวนให้ปลาคาร์พได้หรือไม่เพราะมันถูกกฎหมาย 100%


นั่นได้รับการรับประกันหรือเป็นเพียงแนวทางปฏิบัติทั่วไปที่คอมไพเลอร์ในปัจจุบันใช้กัน?
gha.st

1
ตัวแปรแบบคงที่เริ่มต้นเป็น 0 ซึ่งทำสิ่งที่ถูกต้องสำหรับพอยน์เตอร์ด้วยเช่นกัน (เช่นตั้งค่าเป็น NULL ไม่ใช่บิตทั้งหมด 0) ลักษณะการทำงานนี้ได้รับการรับรองโดยมาตรฐาน
Alok Singhal

1
การเริ่มต้นข้อมูลคงที่เป็นศูนย์ได้รับการรับรองโดยมาตรฐาน C และ C ++ ไม่ใช่แค่การปฏิบัติทั่วไปเท่านั้น
groovingandi

1
อาจเป็นเพราะบางคนต้องการให้แน่ใจว่าสแต็กของพวกเขาอยู่ในแนวเดียวกันพวกเขาประกาศตัวแปรทั้งหมดไว้ล่วงหน้าที่ด้านบนของฟังก์ชัน? บางทีพวกเขากำลังเขียนในภาษา ac ที่ต้องการสิ่งนี้?
KitsuneYMG

1

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

จริงๆแล้วโดยสรุปพวกเขาจะเริ่มต้นในแง่ที่ว่าในเวลาลิงก์ตัวแปรตัวชี้จะได้รับที่อยู่ ในโค้ดตัวอย่างของคุณด้านบนมีการรับประกันว่าจะขัดข้องหรือสร้าง SIGSEGV

เพื่อความมีสติควรเริ่มต้นพอยน์เตอร์เป็น NULL เสมอด้วยวิธีนี้หากมีความพยายามที่จะลดทอนความหมายโดยไม่มีmallocหรือ newจะแจ้งให้โปรแกรมเมอร์ทราบถึงสาเหตุที่โปรแกรมทำงานผิดพลาด

หวังว่านี่จะช่วยและสมเหตุสมผล


0

ถ้า C ++ เริ่มต้นพอยน์เตอร์แล้วคน C ที่บ่นว่า "C ++ ช้ากว่า C" ก็จะมีบางอย่างที่ต้องรอ;)


นั่นไม่ใช่เหตุผลของฉัน เหตุผลของฉันคือถ้าฮาร์ดแวร์มี ROM 512 ไบต์และ RAM 128 ไบต์และคำสั่งพิเศษให้เป็นศูนย์ตัวชี้จะมีค่าแม้แต่หนึ่งไบต์ซึ่งเป็นเปอร์เซ็นต์ที่ค่อนข้างใหญ่ของโปรแกรมทั้งหมด ฉันต้องการไบต์นั้น!
Jerry Jeremiah

0

C ++ มาจากพื้นหลัง C - และมีสาเหตุบางประการที่กลับมาจากสิ่งนี้:

C มากกว่า C ++ คือการแทนที่ภาษาแอสเซมบลี มันไม่ได้ทำอะไรที่คุณไม่ได้บอกให้ทำ ดังนั้น: หากคุณต้องการโมฆะ - ทำ!

นอกจากนี้หากคุณโมฆะสิ่งต่างๆในภาษา Bare-Metal เช่น C คำถามเกี่ยวกับความสอดคล้องโดยอัตโนมัติจะครอบตัด: หากคุณทำบางสิ่งบางอย่าง - มันควรจะเป็นศูนย์โดยอัตโนมัติหรือไม่? โครงสร้างที่สร้างบนสแต็กล่ะ ไบต์ทั้งหมดควรเป็นศูนย์หรือไม่ แล้วตัวแปรทั่วโลกล่ะ? สิ่งที่เกี่ยวกับคำสั่งเช่น "(* 0x18);" นั่นไม่ได้หมายความว่าตำแหน่งหน่วยความจำ 0x18 ควรเป็นศูนย์หรือไม่?


จริงๆแล้วใน C ถ้าคุณต้องการจัดสรรหน่วยความจำทั้งหมดเป็นศูนย์คุณสามารถcalloc()ใช้ได้
David Thornley

1
แค่ประเด็นของฉัน - ถ้าคุณต้องการทำคุณทำได้ แต่มันไม่ได้ทำเพื่อคุณโดยอัตโนมัติ
gha.st

0

คำแนะนำที่คุณพูดถึงคืออะไร?

เพื่อความปลอดภัยของข้อยกเว้นมักจะใช้auto_ptr, shared_ptr, weak_ptrและสายพันธุ์อื่น ๆ ของพวกเขา จุดเด่นของรหัสที่ดีคือคนที่ไม่รวมสายเดียวที่จะ
delete


3
ตั้งแต่ C ++ 11 ชุนและแทนauto_ptr unique_ptr
Deduplicator

-2

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

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


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