ใครเป็นผู้ลบหน่วยความจำที่จัดสรรระหว่างการดำเนินการใหม่ซึ่งมีข้อยกเว้นในตัวสร้าง

ฉันไม่อยากจะเชื่อเลยจริงๆ ว่าฉันไม่สามารถหาคำตอบที่ชัดเจนสำหรับเรื่องนี้ได้...

คุณจะเพิ่มหน่วยความจำที่จัดสรรได้อย่างไรหลังจากตัวสร้างคลาส C++ ส่งข้อยกเว้น ในกรณีที่เริ่มต้นโดยใช้ตัวดำเนินการ new เช่น.:

class Blah
{
public:
  Blah()
  {
    throw "oops";
  }
};

void main()
{
  Blah* b = NULL;
  try
  {
    b = new Blah();
  }
  catch (...)
  {
    // What now?
  }
}

เมื่อฉันลองสิ่งนี้ b จะเป็น NULL ในบล็อก catch (ซึ่งสมเหตุสมผล)

เมื่อทำการดีบั๊ก ฉันสังเกตเห็นว่าคอนโรลเข้าสู่รูทีนการจัดสรรหน่วยความจำก่อนที่จะกระทบกับคอนสตรัคเตอร์

สิ่งนี้บนเว็บไซต์ MSDN ดูเหมือนว่าจะยืนยันสิ่งนี้:

เมื่อ new ถูกใช้เพื่อจัดสรรหน่วยความจำสำหรับอ็อบเจ็กต์คลาส C++ ตัวสร้างของอ็อบเจ็กต์จะถูกเรียกหลังจากจัดสรรหน่วยความจำแล้ว

ดังนั้น โปรดทราบว่าตัวแปรโลคัล b ไม่เคยถูกกำหนดไว้ (เช่น เป็น NULL ใน catch block) คุณจะลบหน่วยความจำที่จัดสรรได้อย่างไร

คงจะดีถ้าได้รับคำตอบข้ามแพลตฟอร์มเกี่ยวกับเรื่องนี้ นั่นคือข้อมูลจำเพาะ C ++ พูดว่าอย่างไร

คำชี้แจง: ฉันไม่ได้พูดถึงกรณีที่คลาสจัดสรรหน่วยความจำใน c'tor แล้วจึงโยน ฉันซาบซึ้งที่ในกรณีเหล่านั้น d'tor จะไม่ถูกเรียก ฉันกำลังพูดถึงหน่วยความจำที่ใช้ในการจัดสรรวัตถุ THE (Blah ในกรณีของฉัน)


person John    schedule 04.11.2009    source แหล่งที่มา
comment
คุณไม่ควรทำการยกของหนักในตัวสร้างเลย ปล่อยให้มันเป็นวิธีการเริ่มต้นบางอย่าง   -  person jldupont    schedule 04.11.2009
comment
ฉันเห็นด้วยกับ jldupont แต่ถึงกระนั้น นี่เป็นคำถามที่น่าสนใจ   -  person Ben S    schedule 04.11.2009
comment
คุณปลอดภัย. หาก Constructor ทำการขว้าง หน่วยความจำอ็อบเจ็กต์จะถูกยกเลิกการจัดสรรแล้ว (โปรดใช้ความระมัดระวังกับสมาชิกเนื่องจากไม่มีการเรียก destructor)   -  person Martin York    schedule 04.11.2009
comment
ในทางตรงกันข้าม. วัตถุควรจะเริ่มต้นได้อย่างสมบูรณ์ภายใน Constructor เว้นแต่คุณจะไม่สามารถใช้ข้อยกเว้นได้ด้วยเหตุผลบางประการ อ่านภาคผนวก E ของ Stroustrups The C++ Programming Language สำหรับรายละเอียดเพิ่มเติม: www2.research.att .com/~bs/3rd_safe.pdf   -  person Nemanja Trifunovic    schedule 04.11.2009
comment
ส่วนที่ตรงกันข้ามใช้กับโพสต์ของ jldupont ไม่ใช่ของ Martin :)   -  person Nemanja Trifunovic    schedule 04.11.2009
comment
@jldupont: ฉันหวังว่าเราจะลงคะแนนความคิดเห็นของคุณได้ Constructor อยู่ที่นั่นเพื่อปล่อยให้อ็อบเจ็กต์อยู่ในสถานะพร้อมใช้งาน ดังนั้นเราจะไม่ต้องจำไว้ว่าต้องเรียกใช้ฟังก์ชัน init ใดๆ คำแนะนำของคุณคือ IMO แย่มาก   -  person sbi    schedule 04.11.2009
comment
ฉันคิดว่าคำแนะนำในการยกของหนักนี้มาจากหลักเกณฑ์ C ++ ของ Google ฉันไม่ได้สมัครเป็นสมาชิกด้วยตัวเอง   -  person rpg    schedule 05.11.2009
comment
แต่แนวทาง C++ ของ Google ชอบรหัสข้อผิดพลาดมากกว่ารหัสข้อยกเว้น ดังนั้นจึงสมเหตุสมผลสำหรับพวกเขาเนื่องจากไม่มีวิธีรายงานความล้มเหลวจากตัวสร้าง   -  person Matthieu M.    schedule 05.11.2009
comment
ฉันคิดว่าคุณไม่รับประกันว่า b จะเป็นโมฆะ ฉันจะใช้คลาส RAII เพื่อรีเซ็ตเป็นค่าเก่า ในกรณีที่นิพจน์ใหม่เกิดขึ้น หากคุณต้องการพึ่งพาสิ่งนั้น   -  person Johannes Schaub - litb    schedule 05.11.2009
comment
ฉันอยู่กับ @sbi; และในภาษา C++ สมัยใหม่ แนวคิดนี้เรียกว่า RAII: Resource Acquisition is Initialization เมื่อคุณมีวัตถุบางอย่างที่มีการจัดสรรหน่วยความจำแบบไดนามิก หน่วยความจำควรได้รับการจัดสรรในตัวสร้าง และปล่อยใน destructor โดยส่วนตัวแล้วฉันโอเคกับวิธี init ส่วนตัวถ้า Constructor มีความยาวมาก และถ้า Constructor เป็นที่เดียวที่ใช้เมธอด init นี้   -  person Kaiser Keister    schedule 09.04.2020


คำตอบ (8)


คุณควรอ้างถึงคำถามที่คล้ายกัน ที่นี่ และที่นี่ ก>. โดยพื้นฐานแล้วหาก Constructor ส่งข้อยกเว้น คุณจะปลอดภัยที่หน่วยความจำของวัตถุนั้นจะถูกปลดปล่อยอีกครั้ง แม้ว่าหากมีการอ้างสิทธิ์หน่วยความจำอื่นในระหว่าง Constructor คุณจะต้องปล่อยให้มันเป็นอิสระก่อนที่จะออกจาก Constructor ยกเว้นกรณีนี้

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

person Kosi2801    schedule 04.11.2009
comment
หน่วยความจำว่างแค่ไหน? ฉันสนใจโดยเฉพาะอย่างยิ่งในกรณีที่บางคนอาจใช้โอเปอเรเตอร์ใหม่ของตัวเอง เป็นต้น - person Kylotan; 04.11.2009
comment
การใช้งานตัวดำเนินการใหม่และการลบของคุณเองจะต้องรู้วิธีจัดสรรและปล่อยหน่วยความจำเท่านั้น งานพิเศษนี้ทำโดยคอมไพเลอร์ เมื่อคุณพูดว่า new Blah() คอมไพเลอร์จะสร้างโค้ดเพื่อ (1) เรียกโอเปอเรเตอร์ใหม่ (ซึ่งเพิ่งจัดสรรหน่วยความจำ) (2) เรียก c'tor และ (3) เรียกโอเปอเรเตอร์ Delete หากมีสิ่งผิดปกติเกิดขึ้น - person Adrian McCarthy; 04.11.2009
comment
@Adrian: เพียงเพื่อที่จะอวดรู้ ;-) โทร (3) ถ้า (1) เสร็จสิ้นและ (2) พ่น - person Martin York; 04.11.2009
comment
วุ้ย เยี่ยมเลย ฉันคิดว่าฉันจะบ้าไปแล้ว :-) ขอบคุณสำหรับคำตอบ. - person John; 05.11.2009
comment
PS: ขออภัยที่ถามคำถามที่ครอบคลุมแล้ว - ฉันได้ดูอย่างรวดเร็วก่อน แต่ไม่เห็นคำถามเฉพาะนี้ - person John; 05.11.2009

ถ้าวัตถุไม่สามารถทำลายได้สำเร็จเนื่องจาก Constructor ส่งข้อยกเว้น สิ่งแรกที่จะเกิดขึ้น (สิ่งนี้เกิดขึ้นโดยเป็นส่วนหนึ่งของการจัดการพิเศษของ Constructor) ก็คือตัวแปรสมาชิกทั้งหมดที่ถูกสร้างขึ้นจะถูกทำลาย - หากมีข้อยกเว้นถูกส่งไปในรายการตัวเริ่มต้น ซึ่งหมายความว่าเฉพาะองค์ประกอบที่ตัวเริ่มต้นทำเสร็จแล้วเท่านั้นที่จะถูกทำลาย

จากนั้น หากอ็อบเจ็กต์ได้รับการจัดสรรด้วย new ฟังก์ชันการจัดสรรคืนที่เหมาะสม (operator delete) จะถูกเรียกพร้อมกับอาร์กิวเมนต์เพิ่มเติมเดียวกันกับที่ถูกส่งไปที่ operator new ตัวอย่างเช่น new (std::nothrow) SomethingThatThrows() จะจัดสรรหน่วยความจำด้วย operator new (size_of_ob, nothrow) พยายามสร้าง SomethingThatThrows ทำลายสมาชิกใดๆ ที่สร้างสำเร็จ จากนั้นเรียก operator delete (ptr_to_obj, nothrow) เมื่อมีการเผยแพร่ข้อยกเว้น - มันจะไม่ทำให้หน่วยความจำรั่วไหล

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

person coppro    schedule 04.11.2009
comment
คุณหมายถึง หากวัตถุไม่สามารถ สร้างโครงสร้าง ได้สำเร็จ ...? - person Walter; 21.02.2018

หาก Constructor โยนหน่วยความจำที่จัดสรรให้กับอ็อบเจ็กต์จะถูกส่งกลับไปยังระบบโดยอัตโนมัติอย่างน่าอัศจรรย์

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

หมายเหตุ:
เนื่องจากคนส่วนใหญ่สังเกตว่าสมาชิกอาจจำเป็นต้องทำความสะอาด

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

#include <iostream>

class Base
{
    public:
        Base()  {std::cout << "Create  Base\n";}
        ~Base() {std::cout << "Destroy Base\n";}
};

class Deriv: public Base
{
    public:
        Deriv(int x)    {std::cout << "Create  Deriv\n";if (x > 0) throw int(x);}
        ~Deriv()        {std::cout << "Destroy Deriv\n";}
};

int main()
{
    try
    {
        {
            Deriv       d0(0);  // All constructors/Destructors called.
        }
        {
            Deriv       d1(1);  // Base constructor and destructor called.
                                // Derived constructor called (not destructor)
        }
    }
    catch(...)
    {
        throw;
        // Also note here.
        // If an exception escapes main it is implementation defined
        // whether the stack is unwound. By catching in main() you force
        // the stack to unwind to this point. If you can't handle re-throw
        // so the system exception handling can provide the appropriate
        // error handling (such as user messages).
    }
}
person Martin York    schedule 04.11.2009
comment
... Note the destructor of the class that threw will not be called ... - จุดสำคัญมาก - person iammilind; 21.02.2012

จาก C++ 2003 Standard 5.3.4/17 - ใหม่:

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

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

โปรดทราบว่าสิ่งนี้ไม่เกี่ยวข้องกับสิ่งที่เกิดขึ้นกับทรัพยากรที่ได้รับในตัวสร้าง ซึ่งเป็นความพยายามครั้งแรกของฉันในการตอบคำถามที่กล่าวถึง - และเป็นคำถามที่กล่าวถึงในคำถามที่พบบ่อย บทความ และการโพสต์ต่างๆ

person Michael Burr    schedule 04.11.2009

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

person cmaynard    schedule 04.11.2009

อ้างอิงจากคำถามที่พบบ่อยของ C++ (parashift.com):

[17.4] ฉันควรจัดการทรัพยากรอย่างไรหากตัวสร้างของฉันอาจมีข้อยกเว้น?

สมาชิกข้อมูลทุกคนภายในวัตถุของคุณควรทำความสะอาดความยุ่งเหยิงของตัวเอง

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

ตัวอย่างเช่น แทนที่จะจัดสรรหน่วยความจำให้กับสมาชิกข้อมูล Fred* แบบดิบ ให้ใส่หน่วยความจำที่จัดสรรไว้ในอ็อบเจ็กต์สมาชิก "ตัวชี้อัจฉริยะ" และตัวทำลายของตัวชี้อัจฉริยะนี้จะ delete อ็อบเจ็กต์ Fred เมื่อตัวชี้อัจฉริยะไม่ทำงาน เทมเพลต std::auto_ptr เป็นตัวอย่างของ "ตัวชี้อัจฉริยะ" คุณยังสามารถเขียนตัวชี้อัจฉริยะการนับการอ้างอิงของคุณเอง. คุณยังสามารถ ใช้ตัวชี้อัจฉริยะเพื่อ "ชี้" ไปยังดิสก์ บันทึกหรือวัตถุบนเครื่องอื่น

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

 #include <memory>

 class Fred {
 public:
   typedef std::auto_ptr<Fred> Ptr;
   ...
 };

typedef นั้นทำให้ไวยากรณ์ของโค้ดทั้งหมดที่ใช้อ็อบเจ็กต์ของคุณง่ายขึ้น: ผู้ใช้ของคุณสามารถพูด Fred::Ptr แทน std::auto_ptr<Fred>:

 #include "Fred.h"

 void f(std::auto_ptr<Fred> p);  // explicit but verbose
 void f(Fred::Ptr           p);  // simpler

 void g()
 {
   std::auto_ptr<Fred> p1( new Fred() );  // explicit but verbose
   Fred::Ptr           p2( new Fred() );  // simpler
   ...
 }
person JRL    schedule 04.11.2009
comment
นั่นเป็นการพูดถึงเนื้อหาของวัตถุ ในขณะที่ฉันคิดว่าผู้โพสต์ต้นฉบับกำลังถามอย่างชัดเจนเกี่ยวกับหน่วยความจำที่จัดสรรเพื่อใส่วัตถุ - person Kylotan; 04.11.2009
comment
ไม่ตอบคำถาม. - person Martin York; 04.11.2009
comment
นี่เป็นคำถามที่เกี่ยวข้องกัน ไม่ใช่คำถามที่ถาม สิ่งนี้จะบอกวิธีการเขียน Blah เพื่อให้ Blah สามารถล้างทุกสิ่งที่จัดสรรก่อนที่จะส่งข้อยกเว้น คำถามคือเกี่ยวกับใครเป็นผู้ล้างหน่วยความจำที่จัดสรรให้กับ Blah เอง - person Adrian McCarthy; 04.11.2009

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

try
{
    std::string *l_string =
        (_heap_cleanup_tpl<std::string>(&l_string),
        new std::string(0xf0000000, ' '));
    delete l_string;
}
catch(std::exception &)
{
}

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

เป็นวิธีจัดการกับปัญหาที่คลุมเครือเล็กน้อย แต่ก็ได้ผล ปัญหาอาจเกิดขึ้นเนื่องจากโซลูชันนี้ต้องใช้ตัวดำเนินการใหม่ที่ผู้ใช้กำหนดและตัวดำเนินการลบที่ผู้ใช้กำหนดเพื่อใช้งานร่วมกัน ตัวดำเนินการใหม่/ลบที่ผู้ใช้กำหนดจะต้องเรียกใช้การดำเนินการ new/delete-operators ของไลบรารีมาตรฐาน C++ แต่ฉันได้ละทิ้งสิ่งนั้นไว้เพื่อการบรรยายสรุปและอาศัย malloc() และ free() แทน

มันไม่ใช่คำตอบสุดท้าย แต่ฉันคิดว่ามันคุ้มค่าที่จะทำคำตอบนี้

PS: มีคุณลักษณะ 'ไม่มีเอกสาร' ในโค้ดด้านล่าง ดังนั้นฉันจึงได้ทำการปรับปรุง

รหัสสำหรับวัตถุชั่วคราวเป็นดังนี้:

class _heap_cleanup_helper
{
    public:
    _heap_cleanup_helper(void **p_heap_block) :
        m_heap_block(p_heap_block),
        m_previous(m_last),
        m_guard_block(NULL)
    {
        *m_heap_block = NULL;
        m_last = this;
    }
    ~_heap_cleanup_helper()
    {
        if (*m_heap_block == NULL) operator delete(m_guard_block);
        m_last = m_previous;
    }
    void **m_heap_block, *m_guard_block;
    _heap_cleanup_helper *m_previous;
    static _heap_cleanup_helper *m_last;
};

_heap_cleanup_helper *_heap_cleanup_helper::m_last;

template <typename p_alloc_type>
class _heap_cleanup_tpl : public _heap_cleanup_helper
{
    public:
    _heap_cleanup_tpl(p_alloc_type **p_heap_block) :
        _heap_cleanup_helper((void **)p_heap_block)
    {
    }
};

ตัวดำเนินการใหม่ที่ผู้ใช้กำหนดมีดังนี้:

void *operator new (size_t p_cbytes)
{
    void *l_retval = malloc(p_cbytes);

    if (
        l_retval != NULL &&
        *_heap_cleanup_helper::m_last->m_heap_block == NULL &&
        _heap_cleanup_helper::m_last->m_guard_block == NULL
    )
    {
        _heap_cleanup_helper::m_last->m_guard_block = l_retval;
    }
    if (p_cbytes != 0 && l_retval == NULL) throw std::bad_alloc();

    return l_retval;
}

void operator delete(void *p_buffer)
{
    if (p_buffer != NULL) free(p_buffer);
}
person Bert-Jan    schedule 10.07.2011
comment
วิธีที่ดีที่สุดคือการดำเนินการเฉพาะอย่างใดอย่างหนึ่ง - person Dennis Zickefoose; 10.07.2011
comment
แน่นอนว่าใครๆ ก็อาจตัดสินใจว่าการสูญเสียหน่วยความจำเพียงเล็กน้อย เช่น 'sizeof(std::string)' นั้นคุ้มค่าแก่การกังวลหรือไม่ ให้ผู้ใช้ของคุณเพิ่มหน่วยความจำกิกะไบต์พิเศษในคอมพิวเตอร์ของเขา! - person Bert-Jan; 10.07.2011
comment
ดูเหมือนว่าคุณจะแนะนำว่าโค้ดสำเร็จรูปทั้งหมดนี้จำเป็นเพื่อหลีกเลี่ยงการรั่วไหลของหน่วยความจำที่ไหนสักแห่ง ซึ่งดังที่คำตอบอื่น ๆ ของคำถามอายุสองปีนี้แสดงให้เห็นชัดเจนว่าไม่จำเป็น หรือคุณกำลังให้รายละเอียดโค้ดที่คอมไพเลอร์อาจแทรกเพื่อป้องกันการรั่วไหลของหน่วยความจำเหล่านั้น ในกรณีนี้ นี่เป็นรายละเอียดมากเกินไป... บล็อก try/catch ง่ายๆ ก็จะแสดงประเด็นนี้เช่นกัน ไม่ว่าจะด้วยวิธีใด นี่เป็นคำตอบที่แย่มาก - person Dennis Zickefoose; 10.07.2011
comment
คำตอบของฉันคือคำตอบเดียวที่กล่าวถึงการหลีกเลี่ยงหน่วยความจำรั่ว แทนที่จะหลีกเลี่ยงข้อยกเว้นที่จะข้ามขอบเขตของคอนสตรัคเตอร์ คุณอาจพบว่าคำตอบนั้นแย่มาก แต่เป็นคำตอบเดียวที่สามารถแก้ไขปัญหาตามที่ระบุไว้ได้ เพียงเพิ่มคำสั่งง่ายๆ หนึ่งคำสั่งสำหรับ 'การจัดสรรใหม่' ทุกครั้ง ปัญหาก็จะได้รับการแก้ไข ต้องใส่โค้ดบล็อกสองอันสุดท้ายเพียงครั้งเดียว ข้อเท็จจริงที่แท้จริงของเรื่องนี้ก็คือ หากคุณไม่ใช้ความระมัดระวัง c++ จะยอมให้หน่วยความจำรั่วแอบเข้าไปในโปรแกรมของคุณด้วยวิธีนี้ - person Bert-Jan; 10.07.2011
comment
จากคำตอบที่ยอมรับ: โดยพื้นฐานแล้วหากตัวสร้างส่งข้อยกเว้นคุณจะปลอดภัยที่หน่วยความจำของวัตถุนั้นจะถูกปลดปล่อยอีกครั้ง จากคำตอบที่ได้รับการโหวตสูงสุดถัดไป: จากนั้น หากวัตถุได้รับการจัดสรรด้วย new ฟังก์ชันการจัดสรรคืนที่เหมาะสม (ตัวดำเนินการลบ) จะถูกเรียกพร้อมกับอาร์กิวเมนต์เพิ่มเติมเดียวกันกับที่ถูกส่งผ่านไปยังตัวดำเนินการ new จากคำตอบที่ได้รับการโหวตสูงสุดถัดไป: หาก Constructor โยนหน่วยความจำที่จัดสรรสำหรับวัตถุนั้นจะถูกส่งกลับไปยังระบบโดยอัตโนมัติอย่างน่าอัศจรรย์ จาก gcc: ideone.com/IRxHX คุณกำลังพยายามหลีกเลี่ยงหน่วยความจำรั่วอะไร - person Dennis Zickefoose; 10.07.2011
comment
-1. ถ้า OP ไม่เคยสับสนมาก่อน ตอนนี้เขา/เธอแน่ใจแล้ว! ฮ่าๆ! - person Zach Saw; 13.07.2011

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

class Blah
{
   public:

   Blah()
       {
           if Error
           {
              this.Error = "oops";
           }
        }
};

void main()
{
Blah* b = NULL;

b = new Blah();

if (b.Error == "oops")
{
   delete (b);
   b = NULL;
}
person Danielle    schedule 04.11.2009
comment
ข้อยกเว้นคือเครื่องมือที่เหมาะสมในกรณีนี้ การตั้งค่าสถานะอาจใช้เฉพาะในกรณีที่คุณไม่สามารถใช้ข้อยกเว้นได้ - person JRL; 04.11.2009
comment
พูดตามตรง ฉันคิดว่านี่คงจะแย่กว่านั้นอีก เนื่องจากผู้ใช้ไม่ชัดเจนว่าเมื่อ Constructor ประสบความสำเร็จ วัตถุยังคงอยู่ในสถานะที่ไม่สอดคล้องกัน การปล่อยให้คนอื่นทำความสะอาดก็ไม่ใช่สไตล์ที่ดี ฉันต้องการวิธียกเว้นหากคุณไม่สามารถนำสิ่งที่ทำให้เกิดข้อผิดพลาดออกจากตัวสร้างของคุณได้ - person Kosi2801; 04.11.2009
comment
ค่าส่งคืนที่คุณต้องทดสอบคือสิ่งที่เรา ไม่ ต้องการอย่างแน่นอน! นั่นคือสิ่งที่เรามีใน C แบบธรรมดามาเป็นเวลาสามสิบปีแล้ว และเรามีค่าส่งคืนที่ถูกละเลยไปกี่พันล้านค่าในตอนนี้??? - person Thomas Padron-McCarthy; 04.11.2009
comment
วิธีมาตรฐานในการดำเนินการคือมีข้อยกเว้น และไม่มีอะไรแปลกเกี่ยวกับเรื่องนี้ ส่งคืนค่าเช่นนั้นซึ่งไม่เคยประสบความสำเร็จมาก่อน โดยมีข้อยกเว้น ไม่ว่าเราจะมีวัตถุที่ใช้งานได้หรือไม่มี ดังนั้นเราจึงสามารถใช้มันได้โดยไม่ต้องทดสอบจนเราอาจจะลืมไป - person David Thornley; 04.11.2009