ทำไมไม่ลบตั้งค่าตัวชี้เป็น NULL?


127

ฉันสงสัยเสมอว่าทำไมการตั้งค่าตัวชี้เป็น NULL โดยอัตโนมัติหลังจากลบไม่ได้เป็นส่วนหนึ่งของมาตรฐาน หากได้รับการดูแลแล้วข้อขัดข้องจำนวนมากเนื่องจากตัวชี้ที่ไม่ถูกต้องจะไม่เกิดขึ้น แต่ต้องบอกว่าฉันคิดได้ว่าทำไมมาตรฐานถึง จำกัด สิ่งนี้:

  1. ประสิทธิภาพ:

    คำแนะนำเพิ่มเติมอาจทำให้deleteประสิทธิภาพช้าลง

  2. อาจเป็นเพราะพconstอยน์เตอร์

    จากนั้นอีกครั้งมาตรฐานอาจทำอะไรบางอย่างสำหรับกรณีพิเศษนี้ฉันเดา

ไม่มีใครรู้เหตุผลที่แน่นอนที่ไม่อนุญาตให้ทำเช่นนี้?

คำตอบ:


150

Stroustrupตอบตัวเอง ข้อความที่ตัดตอนมา:

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

แต่ประเด็นหลักที่เขาหยิบยกคือการโต้แย้งของการลบไม่จำเป็นต้องเป็นค่า lvalue


ฉันคิดว่านี่อาจใช้คำอธิบายเพิ่มเติมได้ ฉันไม่แน่ใจด้วยซ้ำว่าเขาพูดอะไร ... ฉันคิดว่าฉันจะต้องกลับมาในภายหลังเมื่อฉันสามารถอุทิศเวลาสองสามชั่วโมงเพื่อค้นคว้าเรื่องนี้จนกว่าฉันจะได้มันมา หรือคุณสามารถอธิบายคำตอบเพื่อช่วยให้เราเข้าใจได้เร็วขึ้น
Gabriel Staples

63

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

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

หากคุณต้องการความปลอดภัยมีตัวชี้อัจฉริยะมากมายไว้คอยบริการหรือจะเขียนเองก็ได้ดีกว่าและฉลาดกว่า


4
จุดดีที่คำนวณที่อยู่แม้ว่าจะเป็นสิ่งที่คุณไม่ได้เห็นบ่อย
ก็ตาม

คุณกำลังพูดถึงตำแหน่งใหม่เมื่อคุณบอกว่าบางครั้งคุณอาจต้องการลบวัตถุในที่อยู่ที่คำนวณได้ ???
Destructor

@PravasiMeet ไม่ฉันหมายถึงบางอย่างเช่นdelete (ptr + i)
sharptooth

39

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


19

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

นอกจากนั้นคุณสามารถสร้างฟังก์ชันของคุณเองที่ทำสิ่งที่คุณต้องการ:

template<typename T>
void deleten(T *&ptr) {
  delete ptr;
  ptr = NULL;
}

12

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


จริง แต่นั่นจะส่งผลให้มีค่าใช้จ่ายเท่ากัน
snemarch

7

deleteส่วนใหญ่จะใช้ในตัวทำลายซึ่งในกรณีนี้การตั้งค่าสมาชิกเป็น NULL จะไม่มีจุดหมาย ไม่กี่บรรทัดต่อมาในตอนปิด}ไม่มีสมาชิกอีกต่อไป ในตัวดำเนินการมอบหมายโดยทั่วไปแล้วการลบจะตามด้วยการมอบหมายอยู่ดี

นอกจากนี้จะทำให้รหัสต่อไปนี้ผิดกฎหมาย:

T* const foo = new T;
delete foo;

6

นี่เป็นอีกเหตุผลหนึ่ง สมมติว่าลบตั้งค่าอาร์กิวเมนต์เป็น NULL:

int *foo = new int;
int *bar = foo;
delete foo;

ควรตั้งค่าแถบเป็น NULL หรือไม่? คุณสามารถสรุปสิ่งนี้ได้หรือไม่?


5

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


4

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


4

ปรัชญาของ C ++ คือ "จ่ายเฉพาะเมื่อคุณใช้" ฉันคิดว่ามันอาจตอบคำถามของคุณได้

บางครั้งคุณอาจมีฮีปของคุณเองซึ่งจะกู้คืนหน่วยความจำที่ถูกลบ .. หรือบางครั้งตัวชี้ที่ไม่ได้เป็นเจ้าของโดยตัวแปรใด ๆ หรือตัวชี้เก็บไว้ในตัวแปรไม่กี่ตัว - อาจเป็นศูนย์เพียงตัวเดียว
อย่างที่คุณเห็นมีปัญหามากมายและปัญหาที่เป็นไปได้


3

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


-1

ฉันเห็นผู้คนให้คำตอบแปลก ๆ สำหรับคำถามนี้

ptr = โมฆะ; คำสั่งง่ายๆเช่นนี้ทำให้ประสิทธิภาพล่าช้าได้อย่างไร

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

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

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

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