Statement:
This example describes the process of resource leakage caused by an exception thrown by the constructor. In this example, we hope to be careful with possible exceptions when writing our own constructor. If the Code does not properly consider exceptions, exceptions may cause leakage of our resources.
The example shows everything:
It is mainly because the AudioClip member in the BookEntry constructor encountered an exception during initialization, which directly caused the heap memory of the constructed Image object to be not properly released. Take a closer look at the code. In the next section, we will provide an example of a perfect solution to this problem through smart pointers.
# Include <iostream> # include <time. h ># include <memory> using namespace std;/* Author: lpstudy Date: Content: more effective C ++ exception Chapter 10th, to prevent resource leakage in constructor, this is an example of resource leakage. You can see on the screen that the new Image resource is actually leaked. */# Define TRACE_FUCTION_AND_LINE (fmt ,...) printf ("[% 30 s: % 4d]" fmt "\ n" ,__ FUNCTION __, _ LINE __, ##__ VA_ARGS _) class Image {public: image (const string & strImgName): m_strImgName (strImgName) {TRACE_FUCTION_AND_LINE ();}~ Image () {TRACE_FUCTION_AND_LINE ();} private: const string & m_strImgName;};/* The AudioClip class is constructed only after the image class is constructed, the following AudioClip throws an exception and can be used to observe the image destructor. In fact, the image memory leakage is caused by the exception that is not called. */Class AudioClip {public: AudioClip (const string & strAudioName): m_strAudioName (strAudioName) {TRACE_FUCTION_AND_LINE (); throw 1; // The BookEntry throws an exception, the Image structure is not called }~ AudioClip () {TRACE_FUCTION_AND_LINE ();} private: const string & m_strAudioName ;};/* The BookEntry constructor initializes the Image and AudioClip, in this way, if the constructor of Image and AudioClip encounters an exception, the BookEntry constructor will immediately return the result, so that the constructed object is not a complete object. */Class BookEntry {public: BookEntry (const string & name, const string & address = "", const string & imageFileName = "", const string & audioclipName = ""): m_strName (name), m_strAddress (address), m_pImage (0), m_pAudioClip (0) {TRACE_FUCTION_AND_LINE (); if (! ImageFileName. empty () {m_pImage = new Image (imageFileName);} if (! AudioclipName. empty () {m_pAudioClip = new AudioClip (audioclipName );}}~ BookEntry () {delete m_pImage; delete m_pAudioClip; TRACE_FUCTION_AND_LINE ();} void Log () {TRACE_FUCTION_AND_LINE ("My Log ------"); throw 1;} private: string m_strName; string m_strAddress; Image * m_pImage; AudioClip * m_pAudioClip;};/* When the constructor is abnormal, stack memory destructor will not be called, causing Image Memory leakage */void TestStackMemory () {try {TRACE_FUCTION_AND_LINE (""); BookEntry bookEntry ("lpstudy", "beijing ", "imageFileName", "audioClipName");} catch (Int e) {TRACE_FUCTION_AND_LINE ("exception int = % d", e) ;}/ * When testing heap memory, when the constructor is abnormal, we can see that pBookEntry has not been fully constructed at this time, and the returned pointer is actually NULL, causing Image Memory leakage */void TestHeapMemory () {BookEntry * pBookEntry = 0; try {TRACE_FUCTION_AND_LINE (""); pBookEntry = new BookEntry ("lpstudy", "beijing", "imageFileName", "audioClipName");} catch (int e) {TRACE_FUCTION_AND_LINE ("exception int = % d", e); TRACE_FUCTION_AND_LINE ("pBookEntry = % 08 p", p BookEntry); delete pBookEntry; // actually delete null, with no meaning} int main () {TRACE_FUCTION_AND_LINE ("Trace BookEntry ....... "); TestStackMemory (); TestHeapMemory (); return 0 ;} /* The code above clearly shows that the destructor of the allocated heap memory Image object will not be executed due to the exception of the BookEntry Constructor (because the destructor of the BookEntry is not executed ), this results in Image Memory leakage. Solution: 1. Add try and catch to the constructor's function body and call the cleanup function during catch. 2. solution 1: if the pointer is const pointer, no. Because the const pointer must be initialized in the member initialization list, the InitImage and InitAudioClip methods must be referenced in this case. The two methods are responsible for try and catch and return the constructed image and audioclip object pointers, initialize the initialization list for Members. This increases the number of member functions, resulting in code expansion and maintenance confusion. 3. solution 3 uses the intelligent pointer auto_ptr, no matter whether the const or non-const pointers have the same processing results, the code is simple and clear, which implements the Code, after all, it has great practical value. */