Common Memory Leaks and Solutions - Select OOD Revelation New / Delete, Array New / Arrray Delete Match Case 1: Call new / delete in the class constructor and the destructor!
Workaround: Check the constructor, in the case of NEW, in the opposite order, match the destructor to add DELETE! Here is two mean: 1> New Match with Delete, Array New / Array Delete Match; 2> Front NEW to match the respective delete more than New NEW; such as: constructor: m_x = new int = 10]; ... m_y = new cstring; destructor: delete m_y; ... delete [] m_x; // For basic data types, use delete, but in order to unify, // is array delete Case 2: Object pointer does not correctly remove nested
That is, an object contains another object in a reference semantic (pointer) instead of value. Workaround: 1> Develop a good pair of coding habits: the pluck memory allocated by the external function, do not release in the call function, and release within the external function; 2> Try to allocate memory in the constructor, and pay attention not to commit Case 1 error; 3> Memory each of the various tubes in the base class / inheritance; (Specific analysis see the following Case 8)
For example: #include
// Melon: Melon, Watermelon; Class Melon {Public: Melon (Char * Var); ~ Melon (); Void Print (Void);
Protected: private: char * m_variety;
Melon :: Melon (char * var) {m_variety = new char [strlen 1]; struct (m_variety, var);
Melon :: ~ Melon () {delete m_variety;
Void Melon :: Print () {std :: cout << "i'm a" << m_variety << "Melon / N";
// meal: Embrace; Class meal {public: meal (char * var, char * res); ~ meal ();
Void Print (void); protected: private: char * m_reastaurant; // Hotel melon * m_pmelon; // method 2 // Melon M_Melon;
MEAL: :: MEAL (CHAR * VAR, CHAR * RES) // Method 2: Change the reference to the value [//: m_melon (var) {m_pmelon = new melon (var); m_reastaurant = new char [strlen (res) 1]; STRCPY (m_reastaurant, res);}
Meal :: ~ meal () {delete m_reastaurant; delete m_pmelon; // modification method 1;}
Void meal :: print () {std :: cout << "i'am a meal out"; m_pmelon-> print (); // method 2 //m_melon.print(); }int main (... ) {COUT << "Case 2: / N"; Meal M1 ("Honeydew", "Four Seasons"); // honey sauce, four seasons hotels; Meal M2 ("Cantaloup", "Brook Manor Pub"); // Snammel, Creek House Bar; m1.print (); m2.print (); return 0;} case 3: When the object array is released, DELETE []; 1> For a single object, a single basic type (such as Int , Double, etc.), we must use Delete, not wrong; 2> For basic type arrays, because there is no need for size parameters, it is possible, it can be used, all, as in the above example, I It has been directly adopted by delete m_variety. It is recommended to use delete [] m_variety; 3> to use the object array of custom objects, you must use Array Delete so that the compiler will call each object before the release. Destructor, and call free release object array space; for example: #include
Class Point {public: Point (int x = 0, int y = 0, char * col = "red"); ~ point (); protected: private: int m_x; int m_y; char * m_color;};
Point :: Point (int X, int y, char * col): m_x (x), m_y (y) {m_color = new char [strlen (color) 1]; strcpy (m_color, col);}
Point :: ~ Point () {delete [] m_color; std :: cout << "in the deconstuctor of point! / N";
INT Main (int Argc, char * argv []) {cout << "case 3: / n"; point * p = new point [5]; delete p; // correct method: // delete [] p; return }
Case 4: Points to arrays consisting of pointers that point to objects not equivalent to an array of objects. That is, the basic type of the array is a pointer to the object. At this time, it is also delete or delete [] (array delete), is not important, the key is that the pointer does not have a destructive function, and the user must call the DELETE statement.
For example: // Point class and case 3; int Main (int Argc, char * argv []) {cout << "case 4: / n"; point ** pptrary = new point * [10]; // The loop assigns a POINT object for each pointer; int i = 0; for (; i <10; i) {PPTRARY [i] = new point (i, i, "green");} // The following statement Did not release 10 Point objects, released only the array // occupied by the array // of their pointer, causing memory leak / (180 = 10 * sizeof (point) 10 * 6; (6 = SizeOf ("Green"))) // delete [] pptrary;
// Correct method: for (i = 0; i <10; i) {delete pptrary [i];} delete [] pptrary; // or delete pPTRARY; RETURN 0;}
Case 5: Missing copy constructor
This is nothing to say, mainly solving the copy constructor of the compiler to the default, it is insufficient! The default copy constructor uses a bit copy, as follows: Point X; Point Y (x); this can cause two Point object x, y, M_Color points to the same "red" string; when an object is released, Another object's m_color becomes a hanging pointer, resulting in an abnormal process;
Workaround: Write your own copy constructor; for the Point class, write the following: Point :: Point (const point & y): m_x (y.m_x), m_y (y.m_y) {m_color = new char [strlen (y. m_color) 1]; :: STRCPY (m_color, y.m_color);}
Case 6: Missing overload assignment operators, the reason is the same as above! Need to pay attention to the details of its implementation: 1> Copy Construction Function The compiler will automatically block yourself, such as: Point X (); // error; however, assignment operation is not; Point x = x; // Compile period Will not go wrong, but the running period will be wrong! The above error is that the compiler has assigned memory for x, but M_Color has not been initialized when calling the copy constructor; suggesting, try not to use this method to initialize During the compilation; 2> Assignment operator must distinguish whether it is assigned; 3> The resources that must be released in the original new operation (of course, other files must be released before assignment, only discussing the memory overflow, slightly Not mentioned!)
Finally, implement the following: const point & points :: Operator = (const point & rhs) {/ / Prevent yourself from copying yourself // This uses a simple address comparison method, more secure is to use COM the same method to compare a unique encoded generation function; if (this! = & r HS) {m_x = rhs.m_x; m_y = rhs.m_y; // Delete the original resource space; // must keep in mind; delete m_color; m_color = new char [strlen (rhs.m_color) 1]; STRCPY (m_color, rhs.m_color);} return * this;}
Note that the leftmost Const declaration may not, to stop the following statement: (x = y) = z; but due to the basic type also support, in order to match the basic type, CASE 7: About NonModifying Common mistakes for operators; the so-called NonModifying operator does not change the value of the operand, and the return result type is the same as the operand; such as the mathematical operator; the relational operator is not satisfied, because its result is a BOOL type; assignment operation The compass is not (=, =, << =, etc.);
The main reason is that everyone may save the results into a local variable, and the return result is a reference (&) in order to efficiency; Solution: 1> Temporary variables as the internal storage unit of the class; insufficient, not suitable for embedding Set of use and multi-thread, such as W = x y z; for example:
// case 7, Solution 1: StaticConst Point & Point :: Operator (Const Point & RHS) Const {Static Point Temp; Temp.m_x = this-> m_x rhs.m_x; temp.m_y = this-> m_y rhs .m_y; // Release the resources of the previous value; delete temp.m_color; temp.m_color = new char [strlen (this-> m_color) Strlen (rhs.m_color) 1]; sprintf (Temp.m_color, "% S% S ", this-> m_color, rhs.m_color); return temp;}
Note that here is simple, there is no consideration of type conversion, the actual binary operator usually implements the form of a friend function, please see Effective C Item 19 for specific judgment methods;
2> Change the semantics as the value semantic; (the best way, but will reduce efficiency) Note that some people may use the pointer method, such as the following: Point * Temp = new point; ... return (* temp); this will result A unnamed object and is on the heap, resulting in memory leaks;
Const Point Point :: Operator Const {Point Temp; Temp.m_x = this-> m_x rhs.m_x; Temp.m_y = this-> m_y rhs.m_y; // Release the previous value Resources; delete temp.m_color; temp.m_color = new char [strlen (this-> m_color) Strlen (rhs.m_color) 1]; sprintf (Temp.m_color, "% s% s", this-> m_color, RHS.M_COLOR); RETURN TEMP;}
CASE 8: It is useless to define a virtual function for the destructor of the base class;
This situation mainly appears in the following case: the base class pointer points to the derived class; for example: apple is a kind of fruit, and banana also IS; SO SOMEONE WRITE SUCH CODES: FRUIT * BASKET [20]; for (INT i = 0 i <10; i) {BASKET [i] = new apple; // Enter fruit information; ...} for (; i <20; i) {Basket [i] = new banana; // Enter banana information; ...} // If the FRUITDE destructor is not a virtual function, the memory overflow (assuming the new statement in the apple or banana constructor, otherwise it will not be) for (i = 0; i <20 ; i) {Delete Basket [i];} Specific implementation is slightly!
Note: 1> This error has hidden when all derived classes do not have a new New operation, and there is no memory overflow; therefore, it is best to follow the following principles: Define the base class constructor as a non-virtual function, then the class Not allowed; 2> If it is not a virtual function, release the base class pointer does not call the sectic function of the derived class, even if it point to a derived class object; 3> No matter whether it is a virtual function, the release party pointer will call the basis The destructor of the class, and the order sequence is unchanged; 4> If the virtual function is released, the base class pointer is released and the pointer points to a derived class, and the secting function of the derived class will be called, and the descent is called. function!