การลบตัวชี้โมฆะปลอดภัยหรือไม่?


96

สมมติว่าฉันมีรหัสต่อไปนี้:

void* my_alloc (size_t size)
{
   return new char [size];
}

void my_free (void* ptr)
{
   delete [] ptr;
}

ปลอดภัยหรือไม่? หรือต้องแคptrchar*ก่อนที่จะลบ?


ทำไมคุณถึงจัดการหน่วยความจำด้วยตัวเอง? คุณกำลังสร้างโครงสร้างข้อมูลอะไร จำเป็นต้องทำการจัดการหน่วยความจำอย่างชัดเจนใน C ++ นั้นค่อนข้างหายาก โดยปกติคุณควรใช้คลาสที่จัดการให้คุณจาก STL (หรือจาก Boost ด้วยการบีบนิ้ว)
Brian

6
สำหรับคนที่อ่านฉันใช้ตัวแปร void * เป็นพารามิเตอร์สำหรับเธรดของฉันใน win c ++ (ดู _beginthreadex) โดยปกติแล้วจะชี้ไปที่ชั้นเรียนอย่างชัดเจน
ryansstack

4
ในกรณีนี้เป็น Wrapper วัตถุประสงค์ทั่วไปสำหรับใหม่ / ลบซึ่งอาจมีสถิติการติดตามการจัดสรรหรือพูลหน่วยความจำที่ปรับให้เหมาะสม ในกรณีอื่น ๆ ฉันเคยเห็นอ็อบเจ็กต์พอยน์เตอร์จัดเก็บเป็นตัวแปรสมาชิกโมฆะ * อย่างไม่ถูกต้องและลบอย่างไม่ถูกต้องในตัวทำลายโดยไม่ส่งกลับไปยังประเภทวัตถุที่เหมาะสม ดังนั้นฉันจึงอยากรู้เกี่ยวกับความปลอดภัย / ข้อผิดพลาด
An̲̳̳drew

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

41
ฉันคิดว่ามีการตั้งคำถามมากเกินไปแทนที่จะตอบคำถาม (ไม่ใช่แค่ที่นี่ แต่ใน SO ทั้งหมด)
Petruza

คำตอบ:


24

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

อย่างไรก็ตามตามที่กล่าวไว้ในคำตอบอื่น ๆ การลบตัวชี้ที่เป็นโมฆะจะไม่เรียกตัวทำลายซึ่งอาจเป็นปัญหาได้ ในแง่นั้นมันไม่ "ปลอดภัย"

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

ดังที่กล่าวไว้ในคำตอบอื่น ๆ นี่คือพฤติกรรมที่ไม่ได้กำหนดใน C ++ โดยทั่วไปเป็นการดีที่จะหลีกเลี่ยงพฤติกรรมที่ไม่ได้กำหนดแม้ว่าหัวข้อนั้นจะซับซ้อนและเต็มไปด้วยความคิดเห็นที่ขัดแย้งกันก็ตาม


9
นี่เป็นคำตอบที่ยอมรับได้อย่างไร? มันไม่สมเหตุสมผลเลยที่จะ "ลบตัวชี้ที่ว่างเปล่า" - ความปลอดภัยเป็นจุดที่สงสัย
Kerrek SB

6
"ไม่มีเหตุผลที่ดีที่จะทำในสิ่งที่คุณกำลังทำอยู่" นั่นคือความคิดเห็นของคุณไม่ใช่ข้อเท็จจริง
rxantos

8
@rxantos ให้ตัวอย่างการตอบโต้ซึ่งการทำในสิ่งที่ผู้เขียนคำถามต้องการให้เป็นความคิดที่ดีใน C ++
Christopher

ผมคิดว่าคำตอบนี้เป็นจริงส่วนใหญ่ที่เหมาะสม แต่ผมยังคิดว่าคำตอบของคำถามนี้ตอบสนองความต้องการอย่างน้อยการกล่าวถึงว่าเป็นพฤติกรรมที่ไม่ได้กำหนด
Kyle Strand

@Christopher ลองเขียนระบบเก็บขยะแบบเดียวซึ่งไม่เจาะจงประเภท แต่ใช้งานได้จริง ความจริงที่ว่าsizeof(T*) == sizeof(U*)สำหรับทุกคนT,Uชี้ให้เห็นว่าควรมีvoid *การใช้งานตัวเก็บขยะแบบไม่มีเทมเพลต 1 รายการ แต่แล้วเมื่อ gc ต้องลบ / ว่างตัวชี้ก็เกิดคำถามนี้ขึ้น เพื่อให้มันใช้งานได้คุณอาจต้องใช้ lambda function destructor wrapper (urgh) หรือคุณจะต้องมีประเภทของ "type as data" แบบไดนามิกซึ่งอนุญาตให้กลับไปกลับมาระหว่างประเภทและสิ่งที่เก็บได้
BitTickler

148

การลบผ่านตัวชี้โมฆะไม่ได้กำหนดโดยมาตรฐาน C ++ - ดูหัวข้อ 5.3.5 / 3:

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

และเชิงอรรถ:

นี่หมายความว่าไม่สามารถลบอ็อบเจ็กต์โดยใช้ตัวชี้ประเภท void * เนื่องจากไม่มีอ็อบเจ็กต์ประเภทโมฆะ

.


6
คุณแน่ใจหรือไม่ว่าคุณพูดถูก? ฉันคิดว่าเชิงอรรถอ้างถึงข้อความนี้: "ในทางเลือกแรก (ลบวัตถุ) ถ้าประเภทคงที่ของตัวถูกดำเนินการแตกต่างจากประเภทไดนามิกประเภทคงที่จะต้องเป็นคลาสพื้นฐานของประเภทไดนามิกของตัวถูกดำเนินการและแบบคงที่ type จะต้องมีตัวทำลายเสมือนหรือไม่ได้กำหนดลักษณะการทำงานในทางเลือกที่สอง (ลบอาร์เรย์) ถ้าประเภทไดนามิกของวัตถุที่จะลบแตกต่างจากประเภทคงที่พฤติกรรมจะไม่ถูกกำหนด " :)
Johannes Schaub - litb

2
คุณพูดถูก - ฉันได้อัปเดตคำตอบแล้ว ฉันไม่คิดว่ามันจะลบล้างประเด็นพื้นฐาน?

ไม่ไม่แน่นอน มันยังบอกว่าเป็น UB ยิ่งไปกว่านั้นตอนนี้มันระบุว่าการลบโมฆะ * คือ UB :)
Johannes Schaub - litb

เติมหน่วยความจำที่อยู่ปลายแหลมของตัวชี้โมฆะด้วยNULLสร้างความแตกต่างให้กับการจัดการหน่วยความจำของแอปพลิเคชันหรือไม่
artu-hnrq

25

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

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

คุณควรแทนที่ใหม่ / ลบ

การลบโมฆะ * อาจจะทำให้หน่วยความจำของคุณว่างอย่างถูกต้องโดยบังเอิญ แต่มันผิดเพราะผลลัพธ์ไม่ได้กำหนดไว้

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


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

ลบส่วนที่เกี่ยวกับขนาดแม้ว่ามาตรฐาน C ++ จะบอกว่าไม่ได้กำหนด ฉันรู้ว่า malloc / free จะใช้งานได้แม้ว่าตัวชี้ที่เป็นโมฆะ *
Brian R.Bondy

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

โปรดดูคำตอบของ @Neil Butterworth คำตอบของเขาควรเป็นคำตอบที่ได้รับการยอมรับในความคิดของฉัน
Brian R.Bondy

2
@keysersoze: โดยทั่วไปฉันไม่เห็นด้วยกับคำพูดของคุณ เพียงเพราะการใช้งานบางอย่างเก็บขนาดก่อนจัดสรรหน่วยความจำไม่ได้หมายความว่าเป็นกฎ

13

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


2
ถ่านไม่มีตัวสร้าง / ตัวทำลาย
rxantos

9

คำถามไม่สมเหตุสมผล ความสับสนของคุณส่วนหนึ่งอาจเกิดจากภาษาที่ผู้คนมักใช้กับdelete:

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

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


เป็นที่ยอมรับว่าคำถามไม่สมเหตุสมผลหากไม่มีบริบทรอบข้าง คอมไพเลอร์ C ++ บางตัวจะยังคงรวบรวมโค้ดไร้สาระดังกล่าวอย่างมีความสุข (หากพวกเขารู้สึกว่ามีประโยชน์อาจเห่าเตือนเกี่ยวกับเรื่องนี้) ดังนั้นคำถามจึงถูกถามเพื่อประเมินความเสี่ยงที่ทราบแล้วของการเรียกใช้รหัสเดิมที่มีการดำเนินการที่ไม่ได้รับคำแนะนำนี้: จะผิดพลาดหรือไม่ รั่วไหลของหน่วยความจำอาร์เรย์อักขระบางส่วนหรือทั้งหมด? อย่างอื่นที่เฉพาะแพลตฟอร์ม?
An̲̳̳drew

ขอบคุณสำหรับคำตอบที่รอบคอบ โหวต!
An̲̳̳drew

1
@ แอนดรูว์: ฉันกลัวว่ามาตรฐานจะค่อนข้างชัดเจนในเรื่องนี้: "ค่าของตัวถูกดำเนินการของdeleteอาจเป็นค่าตัวชี้ว่างตัวชี้ไปยังวัตถุที่ไม่ใช่อาร์เรย์ที่สร้างขึ้นโดยนิพจน์ใหม่ก่อนหน้านี้หรือตัวชี้ไปที่ วัตถุย่อยที่แสดงถึงคลาสพื้นฐานของอ็อบเจ็กต์ดังกล่าวหากไม่เป็นเช่นนั้นพฤติกรรมจะไม่ถูกกำหนด " ดังนั้นหากคอมไพเลอร์ยอมรับรหัสของคุณโดยไม่มีการวินิจฉัยก็ไม่มีอะไรนอกจากบั๊กในคอมไพเลอร์ ...
Kerrek SB

1
@KerrekSB - Re มันไม่มีอะไรนอกจากบั๊กในคอมไพเลอร์ - ฉันไม่เห็นด้วย มาตรฐานระบุว่าพฤติกรรมไม่ได้กำหนด ซึ่งหมายความว่าคอมไพเลอร์ / การนำไปใช้งานสามารถทำอะไรก็ได้และยังคงเป็นไปตามมาตรฐาน หากการตอบสนองของคอมไพเลอร์บอกว่าคุณไม่สามารถลบตัวชี้โมฆะ * ได้ก็ไม่เป็นไร หากการตอบสนองของคอมไพเลอร์คือการลบฮาร์ดไดรฟ์ก็ใช้ได้เช่นกัน OTOH ถ้าการตอบสนองของคอมไพเลอร์ไม่สร้างการวินิจฉัยใด ๆ แต่สร้างโค้ดที่ทำให้หน่วยความจำที่เชื่อมโยงกับตัวชี้นั้นเป็นอิสระแทนก็ไม่เป็นไร นี่เป็นวิธีง่ายๆในการจัดการกับ UB รูปแบบนี้
David Hammen

เพียงเพื่อเพิ่ม: ฉันไม่ยอมรับการใช้delete void_pointerไฟล์. เป็นพฤติกรรมที่ไม่ได้กำหนด โปรแกรมเมอร์ไม่ควรเรียกใช้พฤติกรรมที่ไม่ได้กำหนดแม้ว่าการตอบสนองจะดูเหมือนว่าจะทำในสิ่งที่โปรแกรมเมอร์ต้องการให้ทำก็ตาม
David Hammen

7

ถ้าคุณต้องทำสิ่งนี้จริงๆทำไมไม่ตัดคนกลาง ( newและdeleteตัวดำเนินการ) ออกแล้วโทรไปที่ส่วนกลางoperator newและoperator deleteโดยตรง? (แน่นอนว่าหากคุณกำลังพยายามที่จะใช้เครื่องมือnewและdeleteตัวดำเนินการจริงคุณควรนำไปใช้operator newและoperator deleteใหม่)

void* my_alloc (size_t size)
{
   return ::operator new(size);
}

void my_free (void* ptr)
{
   ::operator delete(ptr);
}

หมายเหตุที่แตกต่างmalloc(), operator newพ่นstd::bad_allocในความล้มเหลว (หรือเรียกว่าnew_handlerหากมีการลงทะเบียน)


ถูกต้องเนื่องจาก char ไม่มีตัวสร้าง / ตัวทำลาย
rxantos

5

เนื่องจากถ่านไม่มีตรรกะตัวทำลายพิเศษ สิ่งนี้จะใช้ไม่ได้

class foo
{
   ~foo() { printf("huzza"); }
}

main()
{
   foo * myFoo = new foo();
   delete ((void*)foo);
}

ไม่ได้รับการเรียกตัวนักแสดง


5

ถ้าคุณต้องการใช้ void * ทำไมคุณไม่ใช้แค่ malloc / ฟรีล่ะ? ใหม่ / ลบเป็นมากกว่าการจัดการหน่วยความจำ โดยทั่วไป new / delete เรียก constructor / destructor และมีหลายสิ่งเกิดขึ้น หากคุณใช้เพียงชนิดในตัว (เช่นถ่าน *) และลบออกผ่านโมฆะ * มันจะใช้ได้ แต่ก็ยังไม่แนะนำ บรรทัดล่างคือใช้ malloc / ฟรีหากคุณต้องการใช้ void * มิฉะนั้นคุณสามารถใช้ฟังก์ชันเทมเพลตเพื่อความสะดวกของคุณ

template<typename T>
T* my_alloc (size_t size)
{
   return new T [size];
}

template<typename T>
void my_free (T* ptr)
{
   delete [] ptr;
}

int main(void)
{
    char* pChar = my_alloc<char>(10);
    my_free(pChar);
}

ฉันไม่ได้เขียนโค้ดในตัวอย่าง - สะดุดกับรูปแบบนี้ที่ใช้ในสถานที่สองสามแห่งผสมผสานการจัดการหน่วยความจำ C / C ++ อย่างอยากรู้อยากเห็นและสงสัยว่าอันตรายเฉพาะคืออะไร
An̲̳̳drew

การเขียน C / C ++ เป็นสูตรสำหรับความล้มเหลว ใครก็ตามที่เขียนนั้นควรเขียนอย่างใดอย่างหนึ่ง
David Thornley

2
@David นั่นคือ C ++ ไม่ใช่ C / C ++ C ไม่มีเทมเพลตและไม่ใช้ใหม่และลบ
rxantos

5

หลายคนแสดงความคิดเห็นแล้วบอกว่าไม่ไม่ปลอดภัยที่จะลบตัวชี้ที่เป็นโมฆะ ฉันเห็นด้วยกับสิ่งนั้น แต่ฉันก็ต้องการเพิ่มว่าหากคุณกำลังทำงานกับพอยน์เตอร์โมฆะเพื่อจัดสรรอาร์เรย์ที่อยู่ติดกันหรือสิ่งที่คล้ายกันคุณสามารถทำได้newเพื่อให้คุณสามารถใช้งานdeleteได้อย่างปลอดภัย (ด้วยอะแฮ่ม , งานพิเศษเล็กน้อย). สิ่งนี้ทำได้โดยการจัดสรรตัวชี้โมฆะไปยังพื้นที่หน่วยความจำ (เรียกว่า 'อารีน่า') จากนั้นส่งตัวชี้ไปยังอารีน่าให้ใหม่ ดูในส่วนนี้ในc ++ คำถามที่พบบ่อย นี่เป็นแนวทางทั่วไปในการใช้งานพูลหน่วยความจำใน C ++


0

แทบจะไม่มีเหตุผลที่จะทำเช่นนี้

ครั้งแรกของทั้งหมดถ้าคุณไม่ทราบชนิดของข้อมูลและสิ่งที่คุณรู้ก็คือว่ามันเป็นvoid*แล้วคุณจริงๆก็ควรจะได้รับการรักษาข้อมูลที่เป็น typeless หยดของข้อมูลไบนารี ( unsigned char*) และการใช้งานmalloc/ freeการจัดการกับมัน . บางครั้งสิ่งนี้จำเป็นสำหรับสิ่งต่างๆเช่นข้อมูลรูปคลื่นและสิ่งที่คล้ายกันซึ่งคุณต้องส่งพvoid*อยน์เตอร์ไปยัง C apis ไม่เป็นไร.

ถ้าคุณทำทราบชนิดของข้อมูล (คือมันมี ctor / dtor) แต่ด้วยเหตุผลบางอย่างที่คุณสิ้นสุดกับvoid*ตัวชี้ (สำหรับเหตุผลที่สิ่งที่คุณมี) แล้วคุณไม่ควรโยนมันกลับไปที่ประเภทที่คุณรู้ว่ามันจะ เป็นและเรียกdeleteมัน


0

ฉันใช้ void *, (aka Unknown types) ในเฟรมเวิร์กของฉันในขณะที่อยู่ในการสะท้อนรหัสและความคลุมเครืออื่น ๆ และจนถึงขณะนี้ฉันไม่มีปัญหาใด ๆ (หน่วยความจำรั่วการละเมิดการเข้าถึง ฯลฯ ) จากคอมไพเลอร์ใด ๆ เฉพาะคำเตือนเนื่องจากการทำงานไม่ได้มาตรฐาน

เหมาะสมอย่างยิ่งที่จะลบสิ่งที่ไม่รู้จัก (โมฆะ *) ตรวจสอบให้แน่ใจว่าตัวชี้เป็นไปตามหลักเกณฑ์เหล่านี้มิฉะนั้นอาจไม่สมเหตุสมผล:

1) ตัวชี้ที่ไม่รู้จักต้องไม่ชี้ไปที่ชนิดที่มีตัวถอดรหัสเล็กน้อยดังนั้นเมื่อร่ายเป็นตัวชี้ที่ไม่รู้จักก็ไม่ควรถูกลบ ลบเฉพาะตัวชี้ที่ไม่รู้จักหลังจากส่งกลับไปยังประเภท ORIGINAL

2) อินสแตนซ์ถูกอ้างถึงเป็นตัวชี้ที่ไม่รู้จักในสแตกที่ถูกผูกไว้หรือหน่วยความจำที่ถูกผูกไว้หรือไม่ หากตัวชี้ที่ไม่รู้จักอ้างถึงอินสแตนซ์บนสแต็กก็ไม่ควรลบ!

3) คุณเป็นบวก 100% หรือไม่ที่ตัวชี้ที่ไม่รู้จักเป็นพื้นที่หน่วยความจำที่ถูกต้อง? ไม่แล้วไม่ควรลบ!

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


0

หากคุณต้องการแค่บัฟเฟอร์ให้ใช้ malloc / free หากคุณต้องใช้ new / delete ให้พิจารณาคลาส Wrapper เล็กน้อย:

template<int size_ > struct size_buffer { 
  char data_[ size_]; 
  operator void*() { return (void*)&data_; }
};

typedef sized_buffer<100> OpaqueBuffer; // logical description of your sized buffer

OpaqueBuffer* ptr = new OpaqueBuffer();

delete ptr;

0

สำหรับกรณีเฉพาะของถ่าน

ถ่านเป็นชนิดที่อยู่ภายในที่ไม่มีตัวทำลายพิเศษ ดังนั้นข้อโต้แย้งที่รั่วไหลจึงเป็นเรื่องที่น่าสงสัย

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

malloc / free จะเร็วกว่าในกรณีนี้ แต่คุณเสียค่ามาตรฐาน :: bad_alloc และต้องตรวจสอบผลลัพธ์ของ malloc การเรียกใช้ตัวดำเนินการใหม่และลบทั่วโลกอาจจะดีกว่าเพราะมันข้ามคนกลาง


1
" sizeof (ถ่าน) มักจะเป็นหนึ่ง " sizeof (ถ่าน) คือหนึ่งเสมอ
ซอกแซก

เมื่อไม่นานมานี้ (2019) ผู้คนคิดว่าnewถูกกำหนดให้โยนจริง นี่ไม่เป็นความจริง. มันขึ้นอยู่กับสวิตช์คอมไพเลอร์และคอมไพเลอร์ ดูตัวอย่าง/GX[-] enable C++ EH (same as /EHsc)สวิตช์MSVC2019 นอกจากนี้ในระบบฝังตัวหลายคนเลือกที่จะไม่จ่ายภาษีประสิทธิภาพสำหรับข้อยกเว้น C ++ ดังนั้นประโยคที่ขึ้นต้นด้วย "But you forfeit std :: bad_alloc ... " จึงน่าสงสัย
BitTickler
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.