ฉันควรใช้คำหลักใหม่ใน C ++ เมื่อใด


272

ฉันใช้ C ++ มาระยะหนึ่งแล้วและฉันก็สงสัยเกี่ยวกับคำหลักใหม่ ฉันควรจะใช้หรือไม่?

1) ด้วยคำหลักใหม่ ...

MyClass* myClass = new MyClass();
myClass->MyField = "Hello world!";

2) ไม่มีคำหลักใหม่ ...

MyClass myClass;
myClass.MyField = "Hello world!";

จากมุมมองของการใช้งานพวกเขาดูเหมือนจะไม่แตกต่างกัน (แต่ฉันแน่ใจว่าพวกเขาเป็น) ... อย่างไรก็ตามภาษาหลักของฉันคือ C # และแน่นอนวิธีที่ 1 คือสิ่งที่ฉันคุ้นเคย

ความยากดูเหมือนจะเป็นวิธีที่ 1 นั้นยากที่จะใช้กับคลาส std C ++

ฉันควรใช้วิธีใด

อัปเดต 1:

ฉันเพิ่งใช้คำหลักใหม่สำหรับหน่วยความจำฮีป (หรือที่เก็บสินค้าฟรี ) สำหรับอาร์เรย์ขนาดใหญ่ซึ่งอยู่นอกขอบเขต (เช่นถูกส่งคืนจากฟังก์ชัน) เมื่อก่อนที่ฉันใช้กองซ้อนซึ่งทำให้องค์ประกอบครึ่งหนึ่งเสียหายนอกขอบเขตเปลี่ยนเป็นการใช้ฮีปเพื่อให้แน่ใจว่าองค์ประกอบนั้นอยู่ในชั้นเชิง เย้!

อัปเดต 2:

เพื่อนของฉันเพิ่งบอกฉันว่ามีกฎง่ายๆสำหรับการใช้newคำหลัก; ทุกครั้งที่คุณพิมพ์พิมพ์newdelete

Foobar *foobar = new Foobar();
delete foobar; // TODO: Move this to the right place.

ซึ่งจะช่วยป้องกันการรั่วไหลของหน่วยความจำเนื่องจากคุณจะต้องลบการลบเสมอ (เช่นเมื่อคุณตัดและวางลงใน destructor หรืออย่างอื่น)


6
คำตอบสั้น ๆ คือใช้เวอร์ชันย่อเมื่อคุณสามารถออกไปได้ :)
2552

11
เทคนิคที่ดีกว่าเสมอเขียนสอดคล้องลบ - การใช้ภาชนะบรรจุ STL และตัวชี้สมาร์ทเช่นและstd::vector std::shared_ptrสิ่งเหล่านี้จะล้อมการโทรnewและdeleteสำหรับคุณดังนั้นคุณจึงมีโอกาสน้อยที่จะรั่วไหลของหน่วยความจำ ยกตัวอย่างเช่นคุณจำไว้เสมอว่าdeleteต้องโยนทิ้งทุกที่ยกเว้นจะถูกโยนทิ้ง? การใส่deleteด้วยมือนั้นยากกว่าที่คุณคิด
AshleysBrain

@nbolton Re: UPDATE 1 - หนึ่งในสิ่งที่สวยงามเกี่ยวกับ C ++ ก็คือว่ามันช่วยให้คุณเก็บผู้ใช้ประเภทที่กำหนดในกองในขณะที่เก็บขยะ Langs เช่น C # บังคับให้คุณสามารถเก็บข้อมูลในกอง การจัดเก็บข้อมูลบนฮีปนั้นใช้ทรัพยากรมากกว่าการเก็บข้อมูลบนสแต็กดังนั้นคุณควรเลือกสแต็กกับฮีปยกเว้นเมื่อ UDT ของคุณต้องการหน่วยความจำจำนวนมากเพื่อจัดเก็บข้อมูล (ซึ่งหมายความว่าวัตถุจะถูกส่งผ่านตามค่าเริ่มต้น) ทางออกที่ดีในการแก้ไขปัญหาของคุณจะได้รับการผ่านอาร์เรย์ฟังก์ชั่นโดยการอ้างอิง
Charles Addis

คำตอบ:


303

วิธีที่ 1 (ใช้new)

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

วิธีที่ 2 (ไม่ได้ใช้new)

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

เท่าที่หนึ่งใช้; คุณเลือกวิธีที่ดีที่สุดสำหรับคุณเนื่องจากข้อ จำกัด ข้างต้น

บางกรณีง่าย:

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

4
หนึ่ง nitpick - ฉันเชื่อว่าตัวดำเนินการใหม่จัดสรรหน่วยความจำจาก "ร้านค้าฟรี" ในขณะที่ malloc จัดสรรจาก "กอง" สิ่งเหล่านี้ไม่ได้รับประกันว่าจะเหมือนกันแม้ว่าในทางปฏิบัติแล้วมักจะเป็น ดูgotw.ca/gotw/009.htm
Fred Larson

4
ฉันคิดว่าคำตอบของคุณอาจชัดเจนกว่าสำหรับใช้ (99% ของเวลาที่ทางเลือกที่ง่ายใช้วิธีที่ 2 บนวัตถุที่ห่อหุ้มซึ่งเรียกใหม่ / ลบในตัวสร้าง / destructor.)
jalf

4
@jalf: วิธีที่ 2 เป็นวิธีที่ไม่ได้ใช้ใหม่: - / ในกรณีใด ๆ มีหลายครั้งที่โค้ดของคุณจะง่ายกว่ามาก (เช่นการจัดการกับกรณีข้อผิดพลาด) โดยใช้วิธีที่ 2 (อันที่ไม่มีใหม่)
Daniel LeCheminant

Nitpick อีกอัน ... คุณควรทำให้ชัดเจนขึ้นว่าตัวอย่างแรกของนิครั่วจากความทรงจำในขณะที่ตัวที่สองของเขาไม่ได้แม้แต่หน้าข้อยกเว้น
Arafangion

4
@ เฟร็ด, อารากังไอออน: ขอบคุณสำหรับความเข้าใจของคุณ; ฉันได้รวมความคิดเห็นของคุณไว้ในคำตอบแล้ว
Daniel LeCheminant

118

มีความแตกต่างที่สำคัญระหว่างทั้งสอง

ทุกอย่างไม่ได้จัดสรรที่มีnewพฤติกรรมเหมือนประเภทค่าใน C # (และคนมักจะบอกว่าวัตถุเหล่านั้นได้รับการจัดสรรในกองซึ่งน่าจะเป็นเรื่องธรรมดา / กรณีที่เห็นได้ชัดมากที่สุด แต่ไม่เป็นความจริงเสมอ. อีกอย่างแม่นยำวัตถุจัดสรรโดยไม่ต้องใช้newมีการจัดเก็บข้อมูลโดยอัตโนมัติ ระยะเวลา ทุกสิ่งที่จัดสรรด้วยnewจะถูกจัดสรรในฮีปและตัวชี้จะถูกส่งคืนเหมือนกับประเภทการอ้างอิงใน C #

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

(และนั่นคือสิ่งที่คล้ายคลึงกับ C # หยุด)

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

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

void foo() {
  bar b;
  bar* b2 = new bar();
}

ฟังก์ชันนี้สร้างสามค่าที่ควรพิจารณา:

ในบรรทัดที่ 1 มันประกาศตัวแปรbประเภทbarบนสแต็ค (ระยะเวลาอัตโนมัติ)

ในบรรทัดที่ 2 มันจะประกาศbarตัวชี้b2บนสแต็ค (ระยะเวลาอัตโนมัติ) และเรียกใหม่การจัดสรรbarวัตถุบนฮีป (ระยะเวลาแบบไดนามิก)

เมื่อฟังก์ชั่นกลับมาสิ่งต่อไปนี้จะเกิดขึ้น: อันดับแรกb2ออกนอกขอบเขต (คำสั่งของการทำลายอยู่ตรงข้ามกับลำดับการก่อสร้างเสมอ) แต่b2เป็นเพียงพอยน์เตอร์ดังนั้นจึงไม่มีอะไรเกิดขึ้น และที่สำคัญหน่วยความจำที่ชี้ไปยัง ( barอินสแตนซ์ของฮีป) ไม่ได้ถูกแตะต้อง เฉพาะตัวชี้เท่านั้นที่เป็นอิสระเนื่องจากตัวชี้เท่านั้นที่มีช่วงเวลาอัตโนมัติ ข้อที่สองbออกนอกขอบเขตดังนั้นเนื่องจากมีระยะเวลาอัตโนมัติตัวทำลายของมันจะถูกเรียกใช้และหน่วยความจำจะถูกปล่อยให้เป็นอิสระ

และbarตัวอย่างบนกองเหรอ? มันอาจจะยังคงอยู่ที่นั่น ไม่มีใครใส่ใจลบดังนั้นเราจึงรั่วหน่วยความจำ

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

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

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

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


2
"ทุกสิ่งที่ไม่ได้รับการจัดสรรใหม่จะถูกวางลงบนสแต็ก"ไม่ได้อยู่ในระบบที่ฉันทำงาน ... มักจะจัดวาง (และไม่ จำกัด ) ข้อมูลส่วนกลาง (คงที่) จะถูกวางในเซ็กเมนต์ของตนเอง ตัวอย่างเช่น. data, .bss ฯลฯ ... ตัวเชื่อมโยง อวดความรู้ฉันรู้ ...
แดน

แน่นอนคุณพูดถูก ฉันไม่ได้คิดถึงข้อมูลสแตติกจริงๆ แน่นอนฉันไม่ดี :)
2552

2
เหตุใดสิ่งใดที่จัดสรรบนสแต็กต้องมีขนาดคงที่
user541686

ไม่เสมอไปมีหลายวิธีในการหลีกเลี่ยง แต่ในกรณีทั่วไปมันทำเพราะอยู่ในสแต็ก ถ้ามันอยู่ที่ด้านบนสุดของสแต็กก็อาจเป็นไปได้ที่จะปรับขนาด แต่เมื่อมีสิ่งอื่นผลักอยู่ด้านบนมันก็คือ "กำแพงใน" ล้อมรอบด้วยวัตถุที่อยู่ทั้งสองข้างดังนั้นจึงไม่สามารถปรับขนาดได้ . ใช่บอกว่ามันก็มีจะมีขนาดคงที่เป็นบิตของความเรียบง่าย แต่มันบ่งบอกถึงความคิดพื้นฐาน (และฉันจะไม่แนะนำ messing เกี่ยวกับฟังก์ชั่น C ที่ช่วยให้คุณมีความคิดสร้างสรรค์เกินไปกับการจัดสรรสแต็ค)
jalf

14

ฉันควรใช้วิธีใด

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

เพื่อแบ่งเบาภาระของการใช้ฟรีร้านค้าคนจัดการได้คิดค้นสิ่งที่ชอบและauto_ptr unique_ptrฉันขอแนะนำให้คุณดูที่สิ่งเหล่านี้ พวกเขาอาจช่วยแก้ไขปัญหาการพิมพ์ของคุณ ;-)


10

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

อย่างที่คนอื่น ๆ พูดคุณต้องการสิ่งใหม่เมื่อวัตถุของคุณต้องการอยู่นอกฟังก์ชันหรือขอบเขตของวัตถุวัตถุนั้นมีขนาดใหญ่มากหรือเมื่อคุณไม่ทราบขนาดของอาร์เรย์ในเวลารวบรวม

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

มีบางกรณีที่ตัวชี้อัจฉริยะไม่ฉลาด อย่าเก็บ std :: auto_ptr <> ไว้ในคอนเทนเนอร์ STL มันจะลบตัวชี้เร็วเกินไปเนื่องจากการคัดลอกภายในคอนเทนเนอร์ อีกกรณีหนึ่งคือเมื่อคุณมีพอยน์เตอร์ STL คอนเทนเนอร์ขนาดใหญ่มากไปยังวัตถุ boost :: shared_ptr <> จะมีค่าใช้จ่ายเป็นจำนวนมากในขณะที่มันกระแทกการอ้างอิงนับขึ้นและลง วิธีที่ดีกว่าที่จะไปในกรณีนั้นคือการวางคอนเทนเนอร์ STL ลงในวัตถุอื่นและให้วัตถุนั้นเป็น destructor ที่จะเรียกใช้การลบบนตัวชี้ทุกตัวในคอนเทนเนอร์


10

คำตอบสั้น ๆ คือ: หากคุณเป็นมือใหม่ใน C ++ คุณไม่ควรใช้newหรือdeleteตัวคุณเอง

คุณควรใช้พอยน์เตอร์อัจฉริยะเช่นstd::unique_ptrและstd::make_unique(หรือน้อยกว่าstd::shared_ptrและstd::make_shared) ด้วยวิธีนี้คุณไม่ต้องกังวลเรื่องการรั่วไหลของหน่วยความจำมากนัก และแม้ว่าคุณจะสูงกว่าปกติแล้ววิธีปฏิบัติที่ดีที่สุดก็คือการห่อหุ้มวิธีการที่กำหนดเองที่คุณใช้newและdeleteในชั้นเรียนขนาดเล็ก (เช่นตัวชี้สมาร์ทที่กำหนดเอง) ที่ทุ่มเทให้กับปัญหาวงจรชีวิตของวัตถุ

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


น่าสนใจเพื่อดูว่าคำตอบอาจมีการเปลี่ยนแปลงอย่างไรเมื่อเวลาผ่านไป)
Wolf

2

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


2

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


1

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

ที่กล่าวว่ามีบางกรณีที่ชัดเจนซึ่งตัวแปรสแต็กไม่เพียงพอ

หากตัวแปรสแต็กมีหน่วยความจำขนาดใหญ่แสดงว่าคุณมีความเสี่ยงที่จะล้นสแต็ก โดยค่าเริ่มต้นขนาดสแต็คของแต่ละเธรดคือ 1 MBบน Windows ไม่น่าเป็นไปได้ที่คุณจะสร้างตัวแปรสแต็กที่มีขนาด 1 MB แต่คุณต้องจำไว้ว่าการใช้งานสแต็กนั้นเป็นแบบสะสม หากฟังก์ชันของคุณเรียกใช้ฟังก์ชันที่เรียกใช้ฟังก์ชันอื่นซึ่งเรียกใช้ฟังก์ชันอื่นซึ่ง ... ตัวแปรสแต็กในฟังก์ชันเหล่านี้ทั้งหมดจะใช้พื้นที่ในสแต็กเดียวกัน ฟังก์ชั่นการเรียกซ้ำสามารถพบปัญหานี้ได้อย่างรวดเร็วขึ้นอยู่กับความลึกของการเรียกซ้ำ หากนี่เป็นปัญหาคุณสามารถเพิ่มขนาดของสแต็ก (ไม่แนะนำ) หรือจัดสรรตัวแปรบนฮีปโดยใช้โอเปอเรเตอร์ใหม่ (แนะนำ)

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


1

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


0

เมธอดที่สองสร้างอินสแตนซ์บนสแต็กพร้อมกับสิ่งต่าง ๆ เช่นสิ่งที่ประกาศintและรายการพารามิเตอร์ที่ส่งผ่านไปยังฟังก์ชัน

วิธีแรกทำให้มีที่ว่างสำหรับตัวชี้บนสแต็กซึ่งคุณได้ตั้งค่าไปยังตำแหน่งในหน่วยความจำที่MyClassมีการจัดสรรใหม่ในฮีป - หรือร้านค้าฟรี

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


-1

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

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