ลบและลบ [] ตัวดำเนินการใน C ++


136

ความแตกต่างระหว่างdeleteและdelete[]ตัวดำเนินการใน C ++ คืออะไร?


คุณอาจพบคำถามนี้เกี่ยวข้องstackoverflow.com/questions/1913343/…
sharptooth

7
ปัญหาเกี่ยวกับการลบและลบ [] เป็นสาเหตุหนึ่งที่ทำให้ฉันชอบพอยน์เตอร์อัจฉริยะและใช้vector<>แทนอาร์เรย์ทุกครั้งที่ทำได้
David Thornley


@DavidThornley หากคุณใช้สมาร์ทพอยน์เตอร์คุณยังจำเป็นต้องทราบถึงความแตกต่างในแง่ที่คุณยังต้องรู้ว่าอย่าเขียนเช่นstd::unique_ptr<int>(new int[3])เพราะมันจะเรียกปกติdeleteในอาร์เรย์ซึ่งเป็นพฤติกรรมที่ไม่ได้กำหนด แต่คุณต้องใช้std::unique_ptr<int[]>
Arthur Tacca

คำตอบ:


151

deleteประกอบ deallocates หน่วยความจำและเรียก destructor newสำหรับวัตถุเดียวที่สร้างขึ้นด้วย

delete []ประกอบ deallocates หน่วยความจำและโทร destructors new []สำหรับอาร์เรย์ของวัตถุที่สร้างขึ้นด้วยการ

การใช้deleteตัวชี้ที่ส่งกลับโดยnew []หรือdelete []บนตัวชี้ที่ส่งกลับโดยnewผลลัพธ์ในพฤติกรรมที่ไม่ได้กำหนด


3
ฉันสงสัยว่าการใช้ลบในอาร์เรย์ประเภทดั้งเดิม [] ใหม่เช่น int หรือ char (ไม่มีตัวสร้าง / ตัวทำลาย) จำเป็นต้องนำไปสู่พฤติกรรมที่ไม่ได้กำหนดด้วยเช่นกัน ดูเหมือนว่าขนาดอาร์เรย์จะไม่ถูกเก็บไว้ที่ใดก็ได้เมื่อใช้ประเภทดั้งเดิม
thomiel

21
หากมาตรฐานไม่ได้กำหนดสิ่งที่จะเกิดขึ้นเมื่อดำเนินการเสร็จสิ้นนั่นก็คือคำจำกัดความ "พฤติกรรมที่ไม่ได้กำหนด" แม้ว่าคอมไพเลอร์ของคุณจะกำหนดสิ่งที่คุณต้องการให้ทำก็ตาม คอมไพเลอร์อื่นอาจทำสิ่งที่แตกต่างไปจากเดิมอย่างสิ้นเชิง
Rob K

ฉันทำข้อผิดพลาดนี้เมื่อฉันมีอาร์เรย์ของสตริง C เช่น "char ** strArray" หากคุณมีอาร์เรย์เหมือนที่ฉันทำคุณต้องวนซ้ำอาร์เรย์และลบ / ปลดปล่อยแต่ละองค์ประกอบจากนั้นลบ / ปลดปล่อย strArray เอง การใช้ "ลบ []" ในอาร์เรย์ฉันใช้ไม่ได้เนื่องจาก (ตามที่ระบุไว้ในความคิดเห็นและคำตอบด้านบน) IT CALLS DESTRUCTORS มันไม่ได้ทำให้แต่ละช่องว่าง
Katianie

88

ตัวdelete[]ดำเนินการใช้เพื่อลบอาร์เรย์ ตัวdeleteดำเนินการใช้เพื่อลบวัตถุที่ไม่ใช่อาร์เรย์ มันเรียกใช้operator delete[]และoperator deleteฟังก์ชันตามลำดับเพื่อลบหน่วยความจำที่อาร์เรย์หรืออ็อบเจ็กต์ที่ไม่ใช่อาร์เรย์ครอบครองหลังจาก (ในที่สุด) เรียกตัวทำลายสำหรับองค์ประกอบของอาร์เรย์หรือวัตถุที่ไม่ใช่อาร์เรย์

ต่อไปนี้แสดงความสัมพันธ์:

typedef int array_type[1];

// create and destroy a int[1]
array_type *a = new array_type;
delete [] a;

// create and destroy an int
int *b = new int;
delete b;

// create and destroy an int[1]
int *c = new int[1];
delete[] c;

// create and destroy an int[1][2]
int (*d)[2] = new int[1][2];
delete [] d;

สำหรับสิ่งnewที่สร้างอาร์เรย์ (ดังนั้นnew type[]หรือnewใช้กับโครงสร้างชนิดอาร์เรย์) Standard จะค้นหาoperator new[]ในคลาสประเภทองค์ประกอบของอาร์เรย์หรือในขอบเขตส่วนกลางและส่งผ่านจำนวนหน่วยความจำที่ร้องขอ มันอาจร้องขอมากกว่าที่N * sizeof(ElementType)มันต้องการ (เช่นเพื่อเก็บจำนวนองค์ประกอบดังนั้นในภายหลังเมื่อลบจะรู้ว่ามีการเรียกตัวทำลายล้างกี่ครั้งให้ทำ) หากคลาสประกาศoperator new[]เพิ่มเติมว่าจำนวนหน่วยความจำยอมรับอีกsize_tพารามิเตอร์ที่สองนั้นจะได้รับจำนวนองค์ประกอบที่จัดสรร - อาจใช้สิ่งนี้เพื่อวัตถุประสงค์ใด ๆ ที่ต้องการ (การดีบัก ฯลฯ ... )

สำหรับสิ่งnewที่สร้างออบเจ็กต์ที่ไม่ใช่อาร์เรย์จะมองหาoperator newในคลาสขององค์ประกอบหรือในขอบเขตส่วนกลาง ผ่านจำนวนหน่วยความจำที่ร้องขอ ( sizeof(T)เสมอกัน)

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

สำหรับdeleteถ้าตัวชี้ที่ส่งผ่านเป็นคลาสพื้นฐานของชนิดของวัตถุจริงคลาสพื้นฐานจะต้องมีตัวทำลายเสมือน (มิฉะนั้นจะไม่ได้กำหนดพฤติกรรม) ถ้าไม่ใช่คลาสพื้นฐานจะมีการเรียกตัวทำลายของคลาสนั้นและoperator deleteในคลาสนั้นหรือโกลบอลoperator deleteจะถูกใช้ ถ้าคลาสพื้นฐานถูกส่งผ่านไปตัวทำลายของชนิดอ็อบเจ็กต์จริงจะถูกเรียกและสิ่งที่operator deleteพบในคลาสนั้นจะถูกใช้หรือถ้าไม่มีเลยoperator deleteจะเรียกglobal หากoperator deleteในคลาสมีพารามิเตอร์ชนิดที่สองsize_tจะได้รับจำนวนองค์ประกอบที่จะยกเลิกการจัดสรร


18

นี่คือการใช้งานพื้นฐานของรูปแบบการจัดสรร / DE จัดสรรใน c ++ malloc/ free, new/ delete, new[]/delete[]

เราจำเป็นต้องใช้ให้สอดคล้องกัน แต่ฉันต้องการเพิ่มความเข้าใจเฉพาะนี้สำหรับความแตกต่างระหว่างdeleteและdelete[]

1) deleteใช้เพื่อยกเลิกการจัดสรรหน่วยความจำที่จัดสรรสำหรับวัตถุเดี่ยว

2) delete[]ใช้เพื่อยกเลิกการจัดสรรหน่วยความจำที่จัดสรรสำหรับอาร์เรย์ของวัตถุ

class ABC{}

ABC *ptr = new ABC[100]

เมื่อเราพูดว่าnew ABC[100]คอมไพเลอร์สามารถรับข้อมูลเกี่ยวกับจำนวนวัตถุที่ต้องจัดสรร (ในที่นี้คือ 100) และจะเรียกตัวสร้างสำหรับแต่ละวัตถุที่สร้างขึ้น

แต่ถ้าเราใช้delete ptrสำหรับกรณีนี้เท่านั้นคอมไพเลอร์จะไม่ทราบจำนวนวัตถุที่ptrชี้ไปและจะจบลงด้วยการเรียกตัวทำลายและการลบหน่วยความจำเพียง 1 วัตถุ (ออกจากการเรียกผู้ทำลายและการจัดสรรวัตถุที่เหลืออีก 99 ชิ้น) ดังนั้นจะมีการรั่วไหลของหน่วยความจำ

เราจึงจำเป็นต้องใช้delete [] ptrในกรณีนี้


3
นี่น่าจะเป็นคำตอบที่ถูกต้อง ไม่มีคำตอบอื่นใดที่กล่าวถึงความแตกต่างที่ชัดเจน: "แต่ในกรณีนี้ถ้าเราใช้เพียงแค่ลบ ptr สำหรับกรณีนี้คอมไพเลอร์จะไม่ทราบจำนวนวัตถุที่ ptr ชี้ไปและจะจบลงด้วยการเรียกตัวทำลายและลบหน่วยความจำเพียง 1 วัตถุ"
Don Larynx

1
เราจะบรรลุสิ่งเดียวกันใน C ได้อย่างไร?
Dogus Ural

@DogusUral ทำไม? ไม่มีตัวทำลายใน C คุณก็แค่free()นี้และนั่น หากคุณใช้รูปแบบตัวทำลายหลอกคุณต้องเรียกมันหนึ่งครั้งสำหรับทุกวัตถุโดยใช้การforวนซ้ำ
Kotauskas

@DonLarynx ความแตกต่างที่ถูกต้องคือการผสมเข้าด้วยกันทำให้เกิดโปรแกรมที่ไม่ดี การดำเนินการอาจจะทราบว่าหลายวัตถุที่จะทำลายหรือมันอาจจะไม่ ได้รับอนุญาตให้ทราบว่าเรียกว่าผิดและยกเลิกโปรแกรมที่แจ้งให้คุณทราบว่าปัญหาอยู่ที่ใด
Caleth

6

ตัวดำเนินการdeleteและdelete []ใช้ตามลำดับเพื่อทำลายอ็อบเจ็กต์ที่สร้างด้วยnewและnew[]กลับไปยังหน่วยความจำที่จัดสรรที่เหลือให้กับตัวจัดการหน่วยความจำของคอมไพเลอร์

วัตถุที่สร้างขึ้นด้วยnewต้องจำเป็นต้องถูกทำลายด้วยdeleteและที่อาร์เรย์ที่สร้างขึ้นด้วยควรจะถูกลบด้วยnew[]delete[]


2

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


ขอบคุณที่ติดต่อกลับมา
Ziffusion


-6

อืม .. บางทีฉันคิดว่ามันเป็นเพียงเพื่อความชัดเจน ตัวดำเนินการdeleteและตัวดำเนินการdelete[]มีความแตกต่างกัน แต่deleteตัวดำเนินการสามารถปล่อยอาร์เรย์ได้เช่นกัน

test* a = new test[100];
delete a;

และตรวจสอบแล้วรหัสนี้ไม่มีการรั่วไหลของความทรงจำ

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