คุณ (จริงๆ) เขียนรหัสที่ปลอดภัยยกเว้น? [ปิด]


312

การจัดการข้อยกเว้น (EH) ดูเหมือนจะเป็นมาตรฐานปัจจุบันและด้วยการค้นหาเว็บฉันไม่สามารถค้นหาความคิดแปลกใหม่หรือวิธีการที่พยายามปรับปรุงหรือแทนที่มัน (ดีมีความแตกต่างบางอย่างอยู่ แต่ไม่มีอะไรแปลกใหม่)

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

ฉันพยายามหลีกเลี่ยง EH และใช้ค่าส่งคืนการโทรกลับหรืออะไรก็ตามที่เหมาะกับวัตถุประสงค์ แต่เมื่อคุณต้องเขียนรหัสที่เชื่อถือได้คุณก็ไม่สามารถเพิกเฉยต่อ EH ได้ในวันนี้ : มันเริ่มต้นด้วยการnew, ซึ่งอาจทำให้เกิดข้อยกเว้นแทนที่จะส่งกลับ 0 (เหมือนในสมัยก่อน) สิ่งนี้ทำให้เกี่ยวกับบรรทัดของรหัส C ++ ใด ๆ ที่เสี่ยงต่อการยกเว้น และสถานที่อื่น ๆ ใน C + + รหัสพื้นฐานโยนข้อยกเว้น ... std lib ทำมันและอื่น ๆ

รู้สึกเหมือนกำลังเดินบนพื้นที่สั่นคลอนดังนั้นตอนนี้เราถูกบังคับให้ดูแลเรื่องข้อยกเว้น!

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

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

คำถามจริงของฉัน:

  • คุณเขียนโค้ดที่ปลอดภัยยกเว้นจริงๆหรือ
  • คุณแน่ใจหรือว่ารหัส "พร้อมใช้การผลิตล่าสุด" นั้นปลอดภัยยกเว้น?
  • คุณแน่ใจได้มั้ยว่ามันคืออะไร?
  • คุณรู้จักและ / หรือใช้ทางเลือกที่ใช้ได้จริงหรือไม่?

44
"EH เข้ามาแทนที่วิธีการล้างค่าเก่า (ค่าส่งคืน .. )" อะไรนะ? ข้อยกเว้นเป็นเพียงการกำหนดเช่นเดียวกับรหัสส่งคืน ไม่มีอะไรสุ่มเกี่ยวกับพวกเขา
rlbond

2
EH ได้มาตรฐานมาเป็นเวลานาน (ตั้งแต่ Ada แม้!)

12
"EH" เป็นตัวย่อที่กำหนดไว้สำหรับการจัดการข้อยกเว้นหรือไม่ ฉันไม่เคยเห็นมันมาก่อน
Thomas Padron-McCarthy

3
กฎของนิวตันนั้นมีผลบังคับใช้ในทุกวันนี้ ความจริงที่ว่าพวกเขาทำนายปรากฏการณ์ที่หลากหลายมานานหลายศตวรรษนั้นสำคัญมาก
David Thornley

4
@frunsi: เฮ้ขอโทษที่ทำให้คุณสับสน! แต่ฉันคิดว่าถ้ามีคำย่อหรือตัวย่อที่แปลกประหลาดและไม่สามารถอธิบายได้จะทำให้ผู้คนหมดกำลังใจมากกว่า
Thomas Padron-McCarthy

คำตอบ:


520

คำถามของคุณยืนยันว่า "การเขียนรหัสที่ปลอดภัยเป็นเรื่องยากมาก" ฉันจะตอบคำถามของคุณก่อนแล้วตอบคำถามที่ซ่อนอยู่ข้างหลังพวกเขา

ตอบคำถาม

คุณเขียนโค้ดที่ปลอดภัยยกเว้นจริงๆหรือ

แน่นอนฉันทำ.

นี่คือเหตุผล Java หายไปจำนวนมากของการอุทธรณ์ของมันให้ฉันเป็น C ++ Programmer (ขาดความหมาย RAII) แต่ฉันกำลัง digressing: นี่คือ C ++ คำถาม

ในความเป็นจริงมันจำเป็นเมื่อคุณจำเป็นต้องทำงานกับรหัส STL หรือ Boost ตัวอย่างเช่นเธรด C ++ ( boost::threadหรือstd::thread) จะส่งข้อยกเว้นเพื่อออกจากระบบอย่างสุภาพ

คุณแน่ใจหรือว่ารหัส "พร้อมใช้การผลิตล่าสุด" นั้นปลอดภัยยกเว้น?

คุณแน่ใจได้มั้ยว่ามันคืออะไร?

การเขียนโค้ดที่ปลอดภัยยกเว้นนั้นเหมือนกับการเขียนโค้ดที่ไม่มีข้อบกพร่อง

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

คุณรู้จักและ / หรือใช้ทางเลือกที่ใช้ได้จริงหรือไม่?

มีไม่มีทางเลือกปฏิบัติใน C ++ (เช่นคุณจะต้องกลับไปที่ C และหลีกเลี่ยงการ c ++ ห้องสมุดเช่นเดียวกับความผิดภายนอกเช่น Windows SEH)

การเขียนรหัสที่ปลอดภัยยกเว้น

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

ตัวอย่างเช่น a newสามารถโยนข้อยกเว้นได้ แต่การกำหนดบิวด์อิน (เช่น int หรือตัวชี้) จะไม่ล้มเหลว การสลับจะไม่ล้มเหลว (ไม่เคยเขียนการสลับการโยน), การstd::list::push_backโยนสามารถ ...

รับประกันข้อยกเว้น

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

  1. ไม่มี : รหัสของคุณไม่ควรเสนอ รหัสนี้จะรั่วไหลทุกอย่างและแยกแยะที่ข้อยกเว้นแรกที่ถูกโยน
  2. พื้นฐาน : นี่คือการรับประกันที่คุณต้องมีอย่างน้อยที่สุดข้อเสนอนั่นคือถ้ามีข้อยกเว้นถูกโยนไม่มีทรัพยากรรั่วไหลออกมาและวัตถุทั้งหมดยังคงเป็นทั้งหมด
  3. strong : การประมวลผลจะสำเร็จหรือส่งข้อยกเว้น แต่ถ้าส่งออกข้อมูลจะอยู่ในสถานะเดียวกับถ้าการประมวลผลไม่ได้เริ่มเลย (ซึ่งจะให้พลังงานการทำธุรกรรมไปที่ C ++)
  4. nothrow / nofail : การประมวลผลจะประสบความสำเร็จ

ตัวอย่างของรหัส

รหัสต่อไปนี้ดูเหมือนว่าถูกต้อง C ++ แต่โดยความจริงแล้วเป็นการรับประกันว่า "ไม่มี" และดังนั้นจึงไม่ถูกต้อง:

void doSomething(T & t)
{
   if(std::numeric_limits<int>::max() > t.integer)  // 1.   nothrow/nofail
      t.integer += 1 ;                              // 1'.  nothrow/nofail
   X * x = new X() ;                // 2. basic : can throw with new and X constructor
   t.list.push_back(x) ;            // 3. strong : can throw
   x->doSomethingThatCanThrow() ;   // 4. basic : can throw
}

ฉันเขียนโค้ดทั้งหมดโดยคำนึงถึงการวิเคราะห์เช่นนี้

การรับประกันต่ำสุดที่เสนอนั้นเป็นพื้นฐาน แต่จากนั้นการเรียงลำดับของแต่ละคำสั่งจะทำให้ฟังก์ชั่นทั้งหมด "ไม่มี" เพราะถ้า 3. พ่น, x จะรั่วไหล

สิ่งแรกที่ต้องทำคือการทำให้ฟังก์ชั่น "พื้นฐาน" นั้นคือการใส่ x ในตัวชี้สมาร์ทจนกว่ามันจะเป็นเจ้าของรายการอย่างปลอดภัย:

void doSomething(T & t)
{
   if(std::numeric_limits<int>::max() > t.integer)  // 1.   nothrow/nofail
      t.integer += 1 ;                              // 1'.  nothrow/nofail
   std::auto_ptr<X> x(new X()) ;    // 2.  basic : can throw with new and X constructor
   X * px = x.get() ;               // 2'. nothrow/nofail
   t.list.push_back(px) ;           // 3.  strong : can throw
   x.release() ;                    // 3'. nothrow/nofail
   px->doSomethingThatCanThrow() ;  // 4.  basic : can throw
}

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

void doSomething(T & t)
{
   // we create "x"
   std::auto_ptr<X> x(new X()) ;    // 1. basic : can throw with new and X constructor
   X * px = x.get() ;               // 2. nothrow/nofail
   px->doSomethingThatCanThrow() ;  // 3. basic : can throw

   // we copy the original container to avoid changing it
   T t2(t) ;                        // 4. strong : can throw with T copy-constructor

   // we put "x" in the copied container
   t2.list.push_back(px) ;          // 5. strong : can throw
   x.release() ;                    // 6. nothrow/nofail
   if(std::numeric_limits<int>::max() > t2.integer)  // 7.   nothrow/nofail
      t2.integer += 1 ;                              // 7'.  nothrow/nofail

   // we swap both containers
   t.swap(t2) ;                     // 8. nothrow/nofail
}

เราสั่งซื้อการดำเนินการอีกครั้งสร้างและตั้งค่าXให้ถูกต้องก่อน หากการดำเนินการใด ๆ ล้มเหลวtจะไม่มีการแก้ไขดังนั้นการดำเนินการ 1 ถึง 3 อาจถือได้ว่า "แข็งแรง": หากมีบางอย่างผิดปกติtจะไม่ได้รับการแก้ไขและXจะไม่รั่วไหลเนื่องจากเป็นตัวชี้สมาร์ท

จากนั้นเราจะสร้างสำเนาt2ของtและทำงานกับสำเนานี้จากการดำเนินการ 4 ถึง 7 หากมีบางสิ่งบางอย่างผิดเพี้ยนt2มีการแก้ไข แต่จากนั้นtยังคงเป็นต้นฉบับ เรายังคงเสนอการรับประกันที่แข็งแกร่ง

จากนั้นเราจะแลกเปลี่ยนและt t2การดำเนินการสลับควรจะไม่ได้รับการแปลใน C ++ ดังนั้นหวังว่าการสลับที่คุณเขียนTนั้นจะไม่เกิดขึ้น (หากไม่ใช่ให้ลองเขียนใหม่เพื่อไม่เป็นการหยุดทำงาน)

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

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

ข้อสรุป

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

แน่นอนว่าคอมไพเลอร์ C ++ จะไม่สำรองการรับประกัน (ในรหัสของฉันฉันมีการรับประกันเป็นแท็ก @warning doxygen) ซึ่งค่อนข้างเศร้า แต่ก็ไม่ควรหยุดคุณจากการพยายามเขียนโค้ดที่ปลอดภัย

ความล้มเหลวปกติเทียบกับข้อผิดพลาด

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

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

ข้อยกเว้นสำหรับความล้มเหลวในการประมวลผลที่ยอดเยี่ยมไม่ใช่สำหรับข้อบกพร่องของรหัส

คำสุดท้าย

ตอนนี้คำถามคือ "นี่มันคุ้มค่าหรือไม่"

แน่นอนมันเป็น มีฟังก์ชั่น "nothrow / no-Fail" การรู้ว่าฟังก์ชั่นจะไม่ล้มเหลวเป็นประโยชน์อย่างมาก ฟังก์ชันเดียวกันสามารถพูดได้ว่าเป็น "strong" ซึ่งช่วยให้คุณสามารถเขียนโค้ดที่มีความหมายของทรานแซคชันเช่นฐานข้อมูลที่มีคุณสมบัติ commit / rollback การคอมมิชชันนั้นเป็นการกระทำปกติของโค้ด

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

ดังนั้นเท่าที่ผมเห็นมันเป็นมูลค่ามัน

แก้ไข 2010-01-29: เกี่ยวกับการแลกเปลี่ยนที่ไม่ทุ่มตลาด

nobar แสดงความคิดเห็นที่ฉันเชื่อว่ามีความเกี่ยวข้องมากเพราะเป็นส่วนหนึ่งของ "คุณจะเขียนโค้ดที่ปลอดภัยได้อย่างไร":

  • [me] การแลกเปลี่ยนจะไม่ล้มเหลว (อย่าแม้แต่เขียน swap การขว้างปา)
  • [nobar] นี่เป็นคำแนะนำที่ดีสำหรับswap()ฟังก์ชั่นที่เขียนขึ้นเอง ควรสังเกตว่าstd::swap()สามารถล้มเหลวตามการดำเนินการที่ใช้ภายใน

ค่าเริ่มต้นstd::swapจะทำสำเนาและการมอบหมายซึ่งสำหรับบางวัตถุสามารถโยนได้ ดังนั้นการสลับค่าเริ่มต้นอาจส่งผ่านไม่ว่าจะใช้สำหรับคลาสของคุณหรือแม้แต่กับคลาส STL เท่าที่ซี ++ มาตรฐานเป็นห่วงการดำเนินการแลกเปลี่ยนสำหรับvector, dequeและlistจะไม่โยนในขณะที่มันอาจจะสำหรับmapถ้า functor เปรียบเทียบสามารถโยนในการก่อสร้างสำเนา (ดูc ++ เขียนโปรแกรมภาษา, รุ่นพิเศษ, ภาคผนวก E, E.4.3 .Swap )

ดูการใช้ Visual C ++ 2008 ในการสลับของเวกเตอร์การสลับของเวกเตอร์จะไม่โยนหากเวกเตอร์สองตัวมีตัวจัดสรรเดียวกัน (เช่นกรณีปกติ) แต่จะทำสำเนาหากพวกเขามีตัวจัดสรรต่างกัน และฉันคิดว่ามันน่าจะโยนได้ในกรณีนี้

ดังนั้นข้อความต้นฉบับยังคงอยู่: ไม่เคยเขียน swap การขว้างปา แต่ต้องจำความคิดเห็นของผู้มีเกียรติ: ให้แน่ใจว่าวัตถุที่คุณแลกเปลี่ยนมีการแลกเปลี่ยนที่ไม่ใช่การขว้างปา

แก้ไข 2011-11-06: บทความที่น่าสนใจ

Dave Abrahamsผู้ให้การค้ำประกันพื้นฐาน / แข็งแรง / ไม่ตัดสัญญาให้เราอธิบายในบทความประสบการณ์ของเขาเกี่ยวกับการทำให้ข้อยกเว้น STL ปลอดภัย:

http://www.boost.org/community/exception_safety.html

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

แก้ไข 2013-05-31: ความคิดเห็นจากdionadar

t.integer += 1;จะไม่มีการรับประกันว่าล้นจะไม่เกิดขึ้นไม่ปลอดภัยยกเว้นและในความเป็นจริงอาจเรียก UB ในทางเทคนิค! (ล้นลงนามคือ UB: C ++ 11 5/4 "ถ้าในระหว่างการประเมินผลของนิพจน์ผลที่ได้คือไม่ได้กำหนดทางคณิตศาสตร์หรือไม่อยู่ในช่วงของค่าที่สามารถแทนได้สำหรับประเภทพฤติกรรมที่ไม่ได้กำหนด") โปรดทราบว่าไม่ได้ลงนาม จำนวนเต็มไม่ล้น แต่ทำการคำนวณในโมดูโลคลาสสมมูล 2 ^ # บิต

Dionadar อ้างถึงบรรทัดต่อไปนี้ซึ่งมีพฤติกรรมที่ไม่ได้กำหนดแน่นอน

   t.integer += 1 ;                 // 1. nothrow/nofail

วิธีแก้ปัญหาที่นี่คือการตรวจสอบว่าจำนวนเต็มมีค่าสูงสุด (ใช้std::numeric_limits<T>::max()) แล้วก่อนที่จะทำการเพิ่ม

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

ฉันแก้ไขรหัสโดยคำนึงถึงความคิดเห็นของ Dionadar


6
ขอบคุณมาก! ฉันยังหวังในสิ่งที่แตกต่าง แต่ฉันยอมรับคำตอบของคุณสำหรับการผสานกับ C ++ และสำหรับคำอธิบายโดยละเอียดของคุณ คุณยังพิสูจน์หักล้าง "สิ่งนี้ทำให้เกี่ยวกับบรรทัดของรหัส C ++ ใด ๆ ที่เสี่ยงต่อการยกเว้น" - ปิด การวิเคราะห์ตามบรรทัดนี้สมเหตุสมผลแล้ว ... ฉันต้องคิดให้ดี
Frunsi

8
"การสลับจะไม่ล้มเหลว" นี่เป็นคำแนะนำที่ดีสำหรับฟังก์ชั่นการแลกเปลี่ยน () ที่กำหนดเอง ควรสังเกตว่า std :: swap () อาจล้มเหลวตามการดำเนินการที่ใช้ภายใน
ดี

7
@ Mehrdad:: "finally" does exactly what you were trying to achieveแน่นอนมันไม่ และเนื่องจากเป็นเรื่องง่ายที่จะสร้างโค้ดที่เปราะบางfinallyแนวคิดในที่สุด "ลองกับทรัพยากร" จึงถูกนำมาใช้ใน Java 7 (นั่นคือ 10 ปีหลังจาก C # usingและอีก 3 ทศวรรษหลังจาก C ++ destructors) นี่คือความเปราะบางที่ฉันวิจารณ์ สำหรับJust because [finally] doesn't match your taste (RAII doesn't match mine, [...]) doesn't mean it's "failing": ในที่นี้อุตสาหกรรมไม่เห็นด้วยกับรสนิยมของคุณเนื่องจากภาษาที่รวบรวมขยะมีแนวโน้มที่จะเพิ่มงบแรงบันดาลใจ RAII (C # usingและ Java ของtry)
paercebal

5
@Mehrdad: RAII doesn't match mine, since it needs a new struct every single darn time, which is tedious sometimesไม่ไม่ คุณสามารถใช้ตัวชี้อัจฉริยะหรือคลาสยูทิลิตี้เพื่อ "ปกป้อง" ทรัพยากร
paercebal

5
@ Mehrdad: "มันบังคับให้คุณทำเสื้อคลุมสำหรับสิ่งที่คุณอาจไม่จำเป็นต้องเสื้อคลุมสำหรับ" - เมื่อการเข้ารหัสในรูปแบบ RAII คุณจะไม่จำเป็นต้องห่อใด ๆ : Ressource เป็นวัตถุและอายุการใช้งานของวัตถุคืออายุการใช้งานทรัพยากร อย่างไรก็ตามฉันมาจากโลก C ++ ปัจจุบันฉันกำลังต่อสู้กับโครงการ Java เปรียบเทียบกับ RAII ใน C ++ นั่นคือ "การจัดการทรัพยากรด้วยตนเอง" ใน Java IS A MESS! ความคิดเห็นของฉัน แต่ Java ได้ทำการซื้อขายเมื่อนานมาแล้ว "mgmt หน่วยความจำอัตโนมัติ" สำหรับ "mgmt ทรัพยากรอัตโนมัติ"
Frunsi

32

การเขียนโค้ดที่ปลอดภัยยกเว้นใน C ++ นั้นไม่มากนักเกี่ยวกับการใช้จำนวนมากลอง {} catch {} บล็อก มันเกี่ยวกับการบันทึกชนิดของการรับประกันรหัสของคุณ

ฉันแนะนำให้อ่านของGuru Of The Weekซีรีส์Herb Sutter โดยเฉพาะอย่างยิ่งตอนที่ 59, 60 และ 61

เพื่อสรุปมีข้อยกเว้นความปลอดภัยสามระดับที่คุณสามารถให้ได้:

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

โดยส่วนตัวแล้วฉันค้นพบบทความเหล่านี้ค่อนข้างช้ารหัส C ++ ของฉันส่วนใหญ่ไม่ปลอดภัยแน่นอน


1
หนังสือของเขา "เจ๋ง C ++" ก็อ่านดี แต่ผมก็ยังพยายามที่จะตั้งคำถามกับแนวคิดของ EH ส ...
Frunsi

8
+1 OP conflates การจัดการข้อยกเว้น (จับพวกเขา) ด้วยความปลอดภัยยกเว้น (มักจะเพิ่มเติมเกี่ยวกับ RAII)
jk

ฉันสงสัยว่ารหัส C ++ ที่ใช้งานได้น้อยมากนั้นเป็นข้อยกเว้นที่ปลอดภัย
Raedwald

18

พวกเราบางคนใช้ข้อยกเว้นมานานกว่า 20 ปี PL / ฉันมีพวกเขาเช่น หลักฐานที่ว่าพวกเขาเป็นเทคโนโลยีใหม่และอันตรายดูเหมือนว่าฉันสงสัย


โปรดอย่าเข้าใจฉันผิดฉัน (หรือกำลังพยายาม) ตั้งคำถามกับ EH และโดยเฉพาะ C ++ EH และฉันกำลังค้นหาทางเลือก บางทีฉันต้องยอมรับมัน (และฉันจะทำถ้าเป็นวิธีเดียว) แต่ฉันคิดว่าอาจมีทางเลือกที่ดีกว่า มันไม่ใช่ว่าผมคิดว่าเป็นแนวคิดใหม่ แต่ใช่ฉันคิดว่ามันสามารถเป็นอันตรายมากขึ้นกว่าจัดการข้อผิดพลาดอย่างชัดเจนด้วยรหัสกลับมา ...
Frunsi

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

ตกลงสมบูรณ์แบบฉันจะใช้ EH และรหัสข้อผิดพลาดและใช้ชีวิตกับมัน ฉันเป็น nitwit ฉันควรได้มาแก้ปัญหาด้วยตัวเอง! ;)
Frunsi

17

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

ตอนนี้สำหรับคำถามที่แท้จริงของคุณ

คุณเขียนโค้ดที่ปลอดภัยยกเว้นจริงๆหรือ

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

คุณแน่ใจหรือว่ารหัส "พร้อมใช้การผลิตล่าสุด" นั้นปลอดภัยยกเว้น?

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

คุณมั่นใจได้หรือไม่?

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

คุณรู้จักและ / หรือใช้ทางเลือกที่ใช้ได้จริงหรือไม่?

ฉันได้ลองหลายรูปแบบในช่วงหลายปีที่ผ่านมาเช่นสถานะการเข้ารหัสในบิตบน (ala HRESULTs ) หรือsetjmp() ... longjmp()แฮ็คที่น่ากลัว ทั้งสองนี้แตกสลายในทางปฏิบัติแม้ว่าในวิธีที่แตกต่างอย่างสิ้นเชิง


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

  • คุณต้องการเห็นtry/ catchเมื่อคุณสามารถทำอะไรบางอย่างเกี่ยวกับข้อยกเว้นเฉพาะ
  • คุณแทบไม่ต้องการเห็นรหัสดิบnewหรือdeleteรหัส
  • Eschew std::sprintf, snprintfและ Array โดยทั่วไป - ใช้std::ostringstreamสำหรับการจัดรูปแบบและแทนที่ Array ด้วยstd::vectorและstd::string
  • หากมีข้อสงสัยให้มองหาฟังก์ชั่นใน Boost หรือ STL ก่อนเริ่มใช้งาน

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


"พฤติกรรมเริ่มต้นไม่รับประกันว่าวัตถุในท้องถิ่นจะถูกทำลายในทุกกรณี" คุณกำลังบอกว่าการตั้งค่าเริ่มต้นของคอมไพเลอร์ Visual Studio C ++ สร้างรหัสที่ไม่ถูกต้องในการเผชิญกับข้อยกเว้น เป็นเช่นนั้นจริงเหรอ?
Raedwald

"คุณแทบจะไม่เคยต้องการที่จะเห็นดิบnewหรือdeleteในรหัส": โดยดิบผมคิดว่าคุณหมายถึงนอกตัวสร้างหรือ destructor
Raedwald

@Raedwald - อีกครั้ง: VC ++: รุ่น VS2005 ของ VC ++ จะไม่ทำลายวัตถุในเครื่องเมื่อข้อยกเว้น SEH ถูกส่งออกไป อ่าน"เปิดใช้ c ++ จัดการข้อยกเว้น" ใน VS2005 ข้อยกเว้น SEH ไม่เรียก destructors ของวัตถุ C ++ ตามค่าเริ่มต้น หากคุณเรียกใช้ฟังก์ชัน Win32 หรือสิ่งใดก็ตามที่กำหนดไว้ใน C-interface DLL คุณต้องกังวลเกี่ยวกับสิ่งนี้เนื่องจากพวกเขาสามารถ (และจะมีโอกาส) โยนข้อยกเว้น SEH ในแบบของคุณ
D.Shawley

@ Raedwald: อีกครั้ง: ดิบ : โดยทั่วไปdeleteไม่ควรใช้นอกเหนือจากการดำเนินการtr1::shared_ptrและไม่ชอบ สามารถนำมาใช้โดยมีเงื่อนไขว่าการใช้งานเป็นสิ่งที่ต้องการnew tr1::shared_ptr<X> ptr(new X(arg, arg));ส่วนที่สำคัญคือผลลัพธ์ของการnewเข้าไปในตัวชี้ที่มีการจัดการโดยตรง หน้าboost::shared_ptrปฏิบัติที่ดีที่สุดอธิบายที่ดีที่สุด
D.Shawley

ทำไมคุณถึงอ้างถึง std :: sprintf (et al) ในชุดของกฎเพื่อความปลอดภัยยกเว้น? สิ่งเหล่านี้ไม่ได้ระบุว่าพวกเขาโยนข้อยกเว้นใด ๆ เช่นen.cppreference.com/w/cpp/io/c/fprintf
mabraham

10

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

ในคำอื่น ๆ , การสร้างรหัสข้อยกเว้นปลอดภัยในระดับที่มีขนาดใหญ่เป็นเรื่องของโปรแกรมการออกแบบไม่ใช่แค่เรื่องของธรรมดาการเข้ารหัส


8
  • คุณเขียนโค้ดที่ปลอดภัยยกเว้นจริงๆหรือ

ฉันตั้งใจอย่างแน่นอน

  • คุณแน่ใจหรือว่ารหัส "พร้อมใช้การผลิตล่าสุด" นั้นปลอดภัยยกเว้น?

ฉันแน่ใจว่าเซิร์ฟเวอร์ 24/7 ของฉันสร้างขึ้นโดยใช้ข้อยกเว้นทำงาน 24/7 และไม่รั่วไหลหน่วยความจำ

  • คุณแน่ใจได้มั้ยว่ามันคืออะไร?

มันยากมากที่จะตรวจสอบว่ารหัสใดถูกต้อง โดยทั่วไปแล้วสามารถไปโดยผลลัพธ์เท่านั้น

  • คุณรู้จักและ / หรือใช้ทางเลือกที่ใช้ได้จริงหรือไม่?

ไม่การใช้ข้อยกเว้นนั้นสะอาดกว่าและง่ายกว่าตัวเลือกใด ๆ ที่ฉันเคยใช้ในช่วง 30 ปีที่ผ่านมาในการเขียนโปรแกรม


30
คำตอบนี้ไม่มีค่า
Matt Joiner

6
@ MattJoiner แล้วคำถามไม่มีค่า
Miles Rout

5

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

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


3

EH ดีโดยทั่วไป แต่การนำไปใช้ของ C ++ นั้นไม่เป็นมิตรมากเพราะเป็นการยากที่จะบอกว่าข้อยกเว้นที่คุณได้รับนั้นครอบคลุมเท่าใด Java เช่นนี้ทำให้ง่ายคอมไพเลอร์จะมีแนวโน้มที่จะล้มเหลวหากคุณไม่จัดการข้อยกเว้นที่เป็นไปได้


2
noexceptมันเป็นเรื่องที่ดีมากที่มีการใช้เหตุผลของ
einpoklum

2

ฉันชอบที่จะทำงานกับ Eclipse และ Java แม้ว่า (ใหม่กับ Java) เพราะมันจะพ่นข้อผิดพลาดในการแก้ไขหากคุณไม่มีตัวจัดการ EH ทำให้สิ่งต่าง ๆ ยากยิ่งที่จะลืมที่จะจัดการกับข้อยกเว้น ...

นอกจากนี้ด้วยเครื่องมือ IDE จะเพิ่มบล็อก try / catch หรือ catch catch อื่นโดยอัตโนมัติ


5
นั่นคือความแตกต่างระหว่างการตรวจสอบ (Java) และข้อยกเว้นที่ไม่ได้ทำเครื่องหมาย (c ++) (Java มีบางอย่างเช่นกัน) ข้อดีของข้อยกเว้นที่ตรวจสอบคือสิ่งที่คุณเขียน แต่มีข้อเสียของตัวเอง Google สำหรับแนวทางที่แตกต่างและปัญหาต่าง ๆ ที่พวกเขามี
David Rodríguez - dribeas

2

พวกเราบางคนชอบภาษาเช่น Java ซึ่งบังคับให้เราประกาศข้อยกเว้นทั้งหมดที่ถูกโยนโดยวิธีการแทนที่จะทำให้พวกเขามองไม่เห็นเช่นใน C ++ และ C #

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

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

เป็นประสบการณ์ของฉันที่ยากที่จะเขียนโค้ดการจัดการข้อยกเว้นใหม่ทั้งหมดใน C ++ ท้ายที่สุดฉันใช้new(nothrow)มาก


4
และคุณกำลังหลีกเลี่ยงไลบรารีมาตรฐานส่วนใหญ่ด้วยหรือไม่ การใช้งานnew(std::nothrow)ไม่เพียงพอ ยังไงก็ตามการเขียนโค้ดที่ปลอดภัยยกเว้นใน C ++ ง่ายกว่าใน Java: en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
avakar

3
ความสามารถในการใช้งานยกเว้นของ Java ที่ตรวจสอบนั้นมีความเข้มงวดสูง ในความเป็นจริงไม่ใช่ภาษาจาวาพวกเขาจะไม่ถือว่าประสบความสำเร็จ นี่คือเหตุผลที่คำสั่ง "Throw" ใน C ++ ตอนนี้ถือว่าล้าสมัยและ C # ไม่เคยพิจารณานำไปใช้อย่างจริงจัง (นี่คือตัวเลือกการออกแบบ) สำหรับ Java เอกสารต่อไปนี้อาจเป็น enlightning: googletesting.blogspot.com/2009/09/…
paercebal

2
เป็นประสบการณ์ของฉันที่การเขียนโค้ดที่ปลอดภัยยกเว้นใน C ++ นั้นไม่ยากและมันก็มีแนวโน้มที่จะนำไปสู่โค้ดที่สะอาดกว่าโดยทั่วไป แน่นอนคุณต้องเรียนรู้ที่จะทำ
David Thornley

2

ฉันลองเขียนรหัสที่ปลอดภัยดีที่สุดแล้ว

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

สามารถเขียนการดำเนินการนี้เพื่อให้การรับประกันข้อยกเว้นที่แข็งแกร่ง? ฉันต้องตั้งหลักพื้นฐานหรือไม่? บรรทัดใดที่อาจมีข้อยกเว้นและฉันจะมั่นใจได้อย่างไรว่าพวกเขาทำพวกเขาจะไม่ทำให้วัตถุเสียหาย


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

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


0

ผู้คนมากมาย (ฉันจะพูดมากที่สุด)

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

คุณต้องทำผิดพลาดในตัวจัดการอย่างแข็งขันเพื่อให้ได้สิ่งที่ไม่ปลอดภัยและมีเพียง catch (... ) {} เท่านั้นที่จะเปรียบเทียบกับการละเว้นรหัสข้อผิดพลาด


4
ไม่จริง. มันง่ายมากที่จะเขียนโค้ดที่ไม่ได้รับการยกเว้น ตัวอย่างเช่น: f = new foo(); f->doSomething(); delete f;หากวิธีการ doSomething มีข้อผิดพลาดแสดงว่าคุณมีหน่วยความจำรั่ว
Kristopher Johnson

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

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

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

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