ลบ []“ รู้” ขนาดของอาร์เรย์ตัวถูกดำเนินการอย่างไร


250
Foo* set = new Foo[100];
// ...
delete [] set;

delete[]คุณไม่ผ่านขอบเขตของอาร์เรย์ไป แต่ข้อมูลนั้นถูกเก็บไว้ที่ไหน? เป็นมาตรฐานหรือไม่


sourceforge.net/projects/fastmmเป็นโอเพ่นซอร์สและแทนที่ memory-manager ที่นี่คุณสามารถค้นหาวิธีการจัดการหน่วยความจำและข้อมูลที่มาจากการจัดสรรและลบความทรงจำ

1
โปรดทราบว่า FastMM นั้นเฉพาะกับคอมไพเลอร์ Delphi / C ++ Builder เท่านั้นไม่ใช่ตัวจัดการหน่วยความจำสำหรับวัตถุประสงค์ทั่วไปของ C ++ มันไม่ได้เขียนด้วยภาษา C ++
Remy Lebeau

คำตอบ:


181

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


4
โปรดทราบว่าสิ่งนี้ใช้ได้กับการจัดสรรอาร์เรย์ใน C ++ เท่านั้น การจัดสรรอื่น ๆ ทั้งหมดขึ้นอยู่กับขนาดของประเภท บางไลบรารีเก็บขนาดการจัดสรรทั้งหมดโดยปกติจะอยู่ในโหมดการดีบักเท่านั้น
Zan Lynx

97
ไม่มีเหตุผลใดที่ข้อมูลนี้ไม่ควรนำเสนอแก่โปรแกรมเมอร์ ฉันสามารถส่งตัวชี้ไปยังฟังก์ชั่นและปลดปล่อยมันได้ แต่เพื่อให้ได้ขนาดตัวเองในฟังก์ชั่นเดียวกันนั้นฉันต้องผ่านพารามิเตอร์พิเศษ มันสมเหตุสมผลหรือไม่?
Mark Ruzon

26
@ Mark ก็จะทำให้มีขนาดเล็กปริมาณของความรู้สึกเพราะในทางทฤษฎีมันไม่ฟรีจัดสรรเสมอเก็บขนาดของการจัดสรรบล็อก (ซึ่งอาจแตกต่างจากขนาดของการร้องขอบล็อก) การออกแบบตัวจัดสรรบางตัวอาจต้องการข้อมูลนี้เพื่อจุดประสงค์ของตัวเองหรืออาจไม่ซับซ้อนพอที่จะใช้ข้อมูลประเภทเพื่อติดตามขนาดของการจัดสรรฮีปแบบไม่ใช้อาร์เรย์เป็นต้นบังคับให้ตัวจัดสรรเพื่อเก็บขนาดที่ร้องขอ ต้องผ่านขนาดอาเรย์ด้วยตัวคุณเอง) อาจเป็นภาระผูกพันเล็กน้อย แต่อาจส่งผลกระทบต่อประสิทธิภาพในการออกแบบตัวจัดสรรที่นึกออก
Doug McClean

33
ขออภัยคำตอบนี้ไม่ได้รับ อะไร QuantumPete อธิบายเป็นพื้น "วิธีการfreeรู้ว่าหน่วยความจำมากเพื่อ deallocate" ใช่ขนาดบล็อกหน่วยความจำถูกเก็บไว้ "ที่ใดที่หนึ่ง" โดยmalloc(ปกติอยู่ในบล็อกของตัวเอง) ดังนั้นนั่นคือวิธีที่จะfreeรู้ อย่างไรก็ตามnew[]/ delete[]เป็นเรื่องราวที่แตกต่าง การทำงานหลังพื้นด้านบนของ/malloc ยังเก็บจำนวนองค์ประกอบที่สร้างขึ้นในบล็อกหน่วยความจำ (เป็นอิสระจาก) เพื่อให้สามารถดึงและใช้หมายเลขนั้นในภายหลังเพื่อเรียกจำนวน destructors ที่เหมาะสม freenew[]mallocdelete[]
AnT

26
เช่นตัวนับสองตัวจะถูกเก็บไว้ในบล็อก: ขนาดบล็อก (โดยmalloc) และจำนวนองค์ประกอบ (โดยnew[]) โปรดทราบว่าอดีตไม่สามารถใช้ในการคำนวณหลังได้เนื่องจากในกรณีทั่วไปขนาดของบล็อกหน่วยความจำอาจมีขนาดใหญ่กว่าที่จำเป็นสำหรับอาร์เรย์ขนาดที่ร้องขอจริงๆ นอกจากนี้โปรดทราบว่าตัวนับองค์ประกอบอาเรย์จำเป็นสำหรับประเภทที่มีตัวทำลายที่ไม่สำคัญเท่านั้น สำหรับประเภท destructor เล็กน้อยเคาน์เตอร์ไม่ได้เก็บไว้โดยและแน่นอนไม่ดึงข้อมูลโดยnew[] delete[]
AnT

23

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

ตัวอย่างวิธีการทำ:

ที่นี่

int* i = new int[4];

คอมไพเลอร์จะจัดสรรsizeof(int)*5ไบต์

int *temp = malloc(sizeof(int)*5)

จะเก็บ "4" ในsizeof(int)ไบต์แรก

*temp = 4;

และตั้ง i

i = temp + 1;

ดังนั้นiจะชี้ไปที่อาร์เรย์ขององค์ประกอบ 4 ไม่ใช่ 5

และการลบ

delete[] i;

จะถูกประมวลผลด้วยวิธีต่อไปนี้:

int *temp = i - 1;
int numbers_of_element = *temp; // = 4
... call destructor for numbers_of_element elements
... that are stored in temp + 1, temp + 2, ... temp + 4 if needed
free (temp)

9

ข้อมูลไม่ได้มาตรฐาน อย่างไรก็ตามในแพลตฟอร์มที่ฉันทำงานกับข้อมูลนี้จะถูกเก็บไว้ในหน่วยความจำก่อนองค์ประกอบแรก ดังนั้นคุณสามารถเข้าถึงมันในทางทฤษฎีและตรวจสอบได้อย่างไรก็ตามมันไม่คุ้มค่า

นี่คือสาเหตุที่คุณต้องใช้การลบ [] เมื่อคุณจัดสรรหน่วยความจำด้วย [] ใหม่เนื่องจากการลบรุ่นอาเรย์รู้ว่า (และที่) จะต้องมองหาจำนวนหน่วยความจำที่เหมาะสม - และเรียกจำนวน destructors ที่เหมาะสม สำหรับวัตถุ


5

โดยทั่วไปจะจัดเรียงในหน่วยความจำเป็น:

[info] [mem ที่คุณขอ ... ]

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

นี่คือการใช้งานขึ้นอยู่กับว่า


4

นี่ไม่ใช่สิ่งที่อยู่ในข้อมูลจำเพาะ - มันขึ้นอยู่กับการใช้งาน


3

มันถูกกำหนดในมาตรฐาน C ++ เพื่อให้คอมไพเลอร์เฉพาะ แปลว่าเวทมนตร์แปล สามารถหยุดได้ด้วยข้อ จำกัด การจัดแนวที่ไม่สำคัญบนแพลตฟอร์มหลักอย่างน้อยหนึ่งแห่ง

คุณสามารถคิดเกี่ยวกับการใช้งานไปได้โดยไม่รู้ว่าdelete[]ถูกกำหนดไว้เฉพาะสำหรับตัวชี้กลับโดยที่ไม่อาจจะเป็นตัวชี้เช่นเดียวกับการส่งกลับโดยnew[] operator new[]การนำไปใช้งานอย่างหนึ่งใน wild คือการเก็บจำนวนอาร์เรย์ใน int แรกที่ส่งคืนโดยoperator new[]และnew[]คืนค่าตัวชี้ที่ผ่านมานั้น (นี่คือเหตุผลที่การจัดแนวที่ไม่สำคัญสามารถทำลายnew[]ได้)

โปรดจำไว้ว่าoperator new[]/operator delete[]! new[]/delete[]=

พลัสนี้เป็นมุมฉากกับวิธี C mallocรู้ขนาดของหน่วยความจำที่จัดสรรโดย


2

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


0

มันไม่ได้มาตรฐาน ในรันไทม์ของ Microsoft ตัวดำเนินการใหม่ใช้ malloc () และตัวดำเนินการลบใช้ฟรี () ดังนั้นในการตั้งค่านี้คำถามของคุณจะเทียบเท่ากับสิ่งต่อไปนี้: ฟรี () รู้ขนาดของบล็อกได้อย่างไร

มีการบันทึกบัญชีเกิดขึ้นเบื้องหลังคือใน C runtime


5
ไม่จริง. ก่อนโทรฟรีการลบ [] จำเป็นต้องโทรหา destructors ก่อน สำหรับเรื่องนี้รู้ขนาดการจัดสรรรวมไม่เพียงพอ ใหม่จริง [] และลบ [] ทำงานแตกต่างกันสำหรับชนิดธรรมดาและ destructed ใน VC ++
Suma

0

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

ประการแรกในขณะที่ในบางระดับระบบของคุณจะต้องรู้วิธีการ 'บล็อกฟรี' บล็อกหน่วยความจำ malloc พื้นฐาน / ฟรี (ซึ่งใหม่ / ลบ / ใหม่ [] / ลบ [] โดยทั่วไปโทร) ไม่จำเสมอว่าหน่วยความจำเท่าไหร่ คุณถามว่ามันจะถูกปัดเศษขึ้น (ตัวอย่างเช่นเมื่อคุณอยู่เหนือ 4K มันจะถูกปัดเศษขึ้นเป็นบล็อกขนาด 4K ถัดไป)

ดังนั้นแม้ว่าจะได้ขนาดบล็อกหน่วยความจำ แต่ก็ไม่ได้บอกเราว่ามีค่าเท่าใดในหน่วยความจำ ed [ใหม่] เนื่องจากอาจมีขนาดเล็กลง ดังนั้นเราต้องเก็บจำนวนเต็มพิเศษเพื่อบอกเราว่ามีกี่ค่า

ยกเว้นหากประเภทที่สร้างขึ้นไม่มีตัวทำลายดังนั้นให้ลบ [] โดยไม่ต้องทำอะไรเลยยกเว้นการเพิ่มบล็อกหน่วยความจำและทำให้ไม่ต้องเก็บอะไร!

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