//泄漏一//类的构造函数与析构函数中未匹配地调用new与delete函数class Point{ int x, y; char * color;public: Point(int, int, char *); /*~Point(){}; This is wrong*/ ~Point();};Point::Point(int new_x, int new_y, char * col){ color = new char[strlen(col)+1]; strcpy(color, col);}//The right way:Point::~Point(){ delete color;}/*泄露2 没有正确清除嵌套指针,对像以引用方式包含了另一对象,而不是用值方式*/#include <cstdlib>#include <iostream>using namespace std;class Melon{ char * variety;public: Melon(char * var); ~Melon(); void print();};Melon::Melon(char * var){ variety = new char[strlen(var)+1]; strcpy(variety, var); } Melon::~Melon(){ delete variety; }void Melon::print(){ cout<<"I'm a "<<variety<<"Melon\n"; }class Meal{ char * restaurant; Melon * m;public: Meal(char * var, char * res); ~Meal(); void print();};Meal::Meal(char * var, char * res): m(new Melon(var)){ restaurant = new char[strlen(res + 1)]; strcpy(restaurant, res); }/*没有释放甜瓜的做法Meal::~Meal(){ delete restaurant; } */ //正确做法:Meal::~Meal(){ delete restaurant; delete m; } void Meal::print(){ cout<<"I'm a Meal owned by "; m->print();}int main(int argc, char *argv[]){ Meal m1("Honeydew", "Four seasons"); Meal m2("Cantaloup", "Brook Manor Pub"); m1.print(); m2.print(); return 0;}//泄露三:释放对象数组时delete中未使用方括号 #include <cstdlib>#include <iostream>using namespace std;class Point{ int x, y; char * color;public: Point(int i = 0, int j = 0, char * col = "Red"); ~Point(); };Point::Point(int i, int j, char * col){ x = i; y = j; color = new char[strlen(col) + 1]; strcpy(color, col); }Point::~Point(){ delete color; cout<<"In the destructor\n"; }int main(int argc, char *argv[]){ Point * p = new Point[5]; //delete p; wrong! delete []p; return 0;}//泄露四:指向对象的指针数组不等同于对象数组//释放对象指针数组与释放对象有很大区别 #include <cstdlib>#include <iostream>using namespace std;class Point{ int x, y; char * color;public: Point(int i = 0, int j = 0, char * col = "Red"); ~Point(); };Point::Point(int i, int j, char * col){ x = i; y = j; color = new char[strlen(col) + 1]; strcpy(color, col); }Point::~Point(){ delete color; cout<<"In the destructor\n"; }int main(int argc, char *argv[]){ //下面代码动态分配了指向10个对象的指针数组(他们本身不是对象) Point ** p = new Point * [10]; int i; //该循环为每个Point指针分配了一个Point对象 for(i = 0; i < 10; i ++) { p[i] = new Point(i, i, "Green"); } /*下面的语句没释放Point对象,释放的只是他们的指针,泄露了10*sizeof(Point) + 60字节的 空间,60是"Green"占用*/ //delete []p; //The right way: for(i = 0; i < 10; i ++) { delete p[i]; } delete p; return 0;}//泄露5:缺少拷贝构造函数//如类的拷贝构造函数没定义则编译器认为是逐个成员复制数据成员,复制指针被定义为将//变量的地址复制给另一变量,这使两个对象拥有指向同一块动态分配内存空间的指针。两//次释放同一内存空间会造成堆的崩溃//!!!隐式的 拷贝构造函数对于大小可变的类来说,会造成内存泄露 #include <cstdlib>#include <iostream>using namespace std;class Point{ int x, y; char * color;public: Point(int i = 0, int j = 0, char * col = "Red"); ~Point(); Point duplicate(Point); //拷贝构造 注意已被注释掉 //Point(const Point &); void print(); };Point::Point(int i, int j, char * col){ x = i; y = j; color = new char[strlen(col) + 1]; strcpy(color, col); }Point::~Point(){ delete color; cout<<"In the destructor\n"; }/*Point::Point(const Point & rhs){ x = rhs.x; y = rhs.y; color = new char[strlen(rhs.color) + 1]; strcpy(color, rhs.color); }*/void Point::print(){ cout<<"I'm a point at (" <<x<<","<<y<<").\n\n"; cout<<"My color is "<<color<<".\n\n";}Point Point::duplicate(Point rhs){//该函数以值方式将Point对象作为函数参数,如未定义copy constructor,则调用隐式的 //copy constructor,又以值方式返回Point对象,又将调用隐式的copy constructor x = rhs.x; y = rhs.y; return (*this); }int main(int argc, char *argv[]){ Point p1(10, 10, "Blue"); Point p2(15, 18, "Green"); /*下面定义隐式调用copy constructor*/ Point p3 = p2; //or Point p3(p1); p1.print(); p2.print(); p3.print(); //该函数两次调用copy constructor p1.duplicate(p2); p1.print(); p2.print(); //color为乱码 p3.print(); //color为乱码 return 0;}//泄露六:缺少重载赋值运算符 与问题五相似 //C++默认为逐个成员拷贝 //类大小可变时,当=左边对象的内部地址与=右边对象内部地址重合时,左边对象中的指针//指向的内存已不再被引用,但这块内存依然未释放。另外两对象都调用destructor可能造//成堆的崩溃 #include <cstdlib>#include <iostream>using namespace std;class Point{ int x, y; char * color;public: Point(int i = 0, int j = 0, char * col = "Red"); ~Point(); void print(); //注意注释掉的 //const Point & operator= (const Point& rhs); };Point::Point(int i, int j, char * col){ x = i; y = j; color = new char[strlen(col) + 1]; strcpy(color, col); }Point::~Point(){ delete color; cout<<"In the destructor\n"; }//下面实现允许Point自身给自身赋值,返回const,使返回值不能作为左值(x = y) = z非//法/*const Point &Point::operator = (const Point & rhs) { if(this == & rhs) { return * this; } x = rhs.x; y = rhs.y; delete color; color = new char[strlen(rhs.color) + 1]; strcpy(color, rhs.color); return * this; }*/void Point::print(){ cout<<"I'm a point at (" <<x<<","<<y<<").\n\n"; cout<<"My color is "<<color<<".\n\n";}int main(int argc, char *argv[]){ Point p1(10, 10, "Blue"); Point p2(15, 18, "Red"); p1.print(); p2.print(); p2 = p1; p1.print(); p2.print(); return 0;}/*泄露七关于nonmodifying元算符重载的常见迷思*///a. 关于nonmodifying/*nonmodifying是指不改变操作数的值且结果是一个与操作数同类型的值的运算符,如数学运算符。而逻辑、关系、赋值不是。Ex_1. 实现nonmodifying主要问题在于返回值。此时,用引用返回局部变量值时,退出函数时,这个引用相关的内存也退回了栈中。函数调用者得到的是一个指向无效,没有分配到内存的对象。*/#include<iostream>using namespace std;class Point{ int x, y; char * color;public: Point(int i = 0, int j = 0, char * col = "Red"); ~Point(); void print(); const Point & operator= (const Point& rhs); const Point & operator+(const Point &); };Point::Point(int i, int j, char * col){ x = i; y = j; color = new char[strlen(col) + 1]; strcpy(color, col); }Point::~Point(){ delete color; cout<<"In the destructor\n"; }const Point &Point::operator = (const Point & rhs) { if(this == & rhs) { return * this; } x = rhs.x; y = rhs.y; delete color; color = new char[strlen(rhs.color) + 1]; strcpy(color, rhs.color); return * this; }void Point::print(){ cout<<"I'm a point at (" <<x<<","<<y<<").\n\n"; cout<<"My color is "<<color<<".\n\n";}const Point &Point::operator +(const Point & rhs){ Point temp; temp.x = x + rhs.x; temp.y = y + rhs.y; delete temp.color; temp.color = new char[strlen(color) + 1 + strlen(rhs.color)]; sprintf(temp.color, "%s%s", color, rhs.color); return temp;//////////////////Attention!!!/////////////////////////}int main(){ Point p1(10, 10, "Blue"); Point p2(5, 18, "Green"); Point p3 = p1 + p2;//复制构造函数参数是一被释放的Point对象,+返回的是指向自动变量temp的隐指针。退出operator +时 //即被析构 //f:\my courses\my homework\programming\project\内存泄露\ex_7\ex_7.cpp(66) : //warning C4172: returning address of local variable or temporary p3.print(); return 0;}/*解决方法:将临时的Point类的对象作为类的内部静态存储对象。它不会在进入退出时被创建/释放,只是进入退出作用域。但是嵌套加法运算符时,如:x+y+z,每次调用都是同一个临时的Point类对象,这会相互破坏所使用的临时变量*//*Ex_2返回静态对象的引用*/#include<iostream>using namespace std;class Point{ int x, y; char * color;public: Point(int i = 0, int j = 0, char * col = "Red"); ~Point(); void print(); const Point & operator= (const Point& rhs); const Point & operator+(const Point &); };Point::Point(int i, int j, char * col){ x = i; y = j; color = new char[strlen(col) + 1]; strcpy(color, col); }Point::~Point(){ delete color; cout<<"In the destructor\n"; }const Point &Point::operator = (const Point & rhs) { if(this == & rhs) { return * this; } x = rhs.x; y = rhs.y; delete color; color = new char[strlen(rhs.color) + 1]; strcpy(color, rhs.color); return * this; }void Point::print(){ cout<<"I'm a point at (" <<x<<","<<y<<").\n\n"; cout<<"My color is "<<color<<".\n\n";}const Point &Point::operator +(const Point & rhs){ static Point temp; //静态,每次调用这个函数时读写都是同一对象 temp.x = x + rhs.x; temp.y = y + rhs.y; delete temp.color; temp.color = new char[strlen(color) + 1 + strlen(rhs.color)]; sprintf(temp.color, "%s%s", color, rhs.color); return temp;}int main(){ Point p1(10, 10, "Blue"); Point p2(5, 18, "Green"); Point p3 = p1 + p2; p3.print(); return 0;}/*Ex_3返回一个泄露内存的动态分配的对象*/#include<iostream>using namespace std;class Point{ int x, y; char * color;public: Point(int i = 0, int j = 0, char * col = "Red"); ~Point(); void print(); const Point & operator= (const Point& rhs); const Point & operator+(const Point &); };Point::Point(int i, int j, char * col){ x = i; y = j; color = new char[strlen(col) + 1]; strcpy(color, col); }Point::~Point(){ delete color; cout<<"In the destructor\n"; }const Point &Point::operator = (const Point & rhs) { if(this == & rhs) { return * this; } x = rhs.x; y = rhs.y; delete color; color = new char[strlen(rhs.color) + 1]; strcpy(color, rhs.color); return * this; }void Point::print(){ cout<<"I'm a point at (" <<x<<","<<y<<").\n\n"; cout<<"My color is "<<color<<".\n\n";}const Point &Point::operator +(const Point & rhs){ Point * temp = new Point; temp->x = x + rhs.x; temp->y = y + rhs.y; delete temp -> color; temp ->color = new char[strlen(color) + 1 + strlen(rhs.color)]; sprintf(temp->color, "%s%s", color, rhs.color); return (*temp); }//指针从来不会隐式地调用析构函数,而且函数的调用员也得不到临时变量地址,内存泄露int main(){ Point p1(10, 10, "Blue"); Point p2(5, 18, "Green"); Point p3 = p1 + p2; p3.print(); return 0;}//所以,返回Point对象的引用是错误的,nonmodifying运算符必须返回一个对象,不可为引用。///////////////////////////////////////泄露七解决方法////////////////////////////////////#include<iostream>using namespace std;class Point{ int x, y; char * color;public: Point(int i = 0, int j = 0, char * col = "Red"); ~Point(); void print(); const Point & operator= (const Point& rhs); const Point operator+(const Point &); };Point::Point(int i, int j, char * col){ x = i; y = j; color = new char[strlen(col) + 1]; strcpy(color, col); }Point::~Point(){ delete color; cout<<"In the destructor\n"; }const Point &Point::operator = (const Point & rhs) { if(this == & rhs) { return * this; } x = rhs.x; y = rhs.y; delete color; color = new char[strlen(rhs.color) + 1]; strcpy(color, rhs.color); return * this; }void Point::print(){ cout<<"I'm a point at (" <<x<<","<<y<<").\n\n"; cout<<"My color is "<<color<<".\n\n";}const Point Point::operator +(const Point & rhs){ Point temp; temp.x = x + rhs.x; temp.y = y + rhs.y; delete temp.color; temp.color = new char[strlen(color) + strlen(rhs.color) + 1]; sprintf(temp.color, "%s%s", color, rhs.color); return (temp); }//指针从来不会隐式地调用析构函数,而且函数的调用员也得不到临时变量地址,内存泄露int main(){ Point p1(10, 10, "Blue"); Point p2(5, 18, "Green"); Point p3 = p1 + p2; p3.print(); return 0;}// 泄露八没将基类析构函数定义为虚函数//#include "stdafx.h"class Fruit{ double weight; char * color;protected: Fruit(double, char *); Fruit(const Fruit &);public: ~Fruit(); /*正确析构函数virtual ~Fruit();*/ virtual void print();};Fruit::Fruit(double w, char * col){ weight = w; color = new char[strlen(col) + 1]; strcpy(color, col);}Fruit::Fruit(const Fruit & rhs){ weight = rhs.weight; color = new char[strlen(rhs.color) + 1]; strcpy(color, rhs.color);}Fruit::~Fruit(){ delete color;}void Fruit::print(){ cout<<"\tFruit weight: "<< weight <<"\n"; cout<<"\tFruit color: "<< color <<"\n";}class Apple:public Fruit{ char * variety;public: Apple (double, char *, char *); Apple (const Apple &); ~Apple(); void print();};Apple::Apple(double w, char * col, char * var):Fruit(w, col){ variety = new char[strlen(var) + 1]; strcpy(variety, var);}Apple::Apple(const Apple & rhs):Fruit(rhs){ variety = new char[strlen(rhs.variety) + 1]; strcpy(variety, rhs.variety);}Apple::~Apple(){ delete variety;}void Apple::print(){ cout<<"Hi, I'm a "<<variety<<" Apple\n"; Fruit::print();}class Banana:public Fruit{ char * export1;public: Banana(double, char * exp); Banana(const Banana & rhs); ~Banana(); void print();};Banana::Banana(double w, char *exp):Fruit(w, "Yellow"){ export1 = new char[strlen(exp)+1]; strcpy(export1, exp);}Banana::~Banana(){ delete export1;}Banana::Banana(const Banana &rhs):Fruit(rhs){ export1 = new char[strlen(rhs.export1)+1]; strcpy(export1, rhs.export1);}void Banana::print(){ cout<<"Hi, I'm a banana from "; cout<< export1 << "\n";}int _tmain(int argc, _TCHAR* argv[]){ Fruit * basket[20]; int i, num; double weight; char color[128], variety[128], answer[128]; /*让用户交互创建水果组*/ cout << "How many fruit in the basket? "; cin >> num; if(num < 0 || num > 20) num = 10; for(i = 0; i < num; i ++) { cout<<"A)pple or B)anana? "; cin >> answer; if(answer[0] == 'a' || answer[0] == 'A') { cout<<"Apple's weight: "; cin >> weight; cout<<"Apple's color: "; cin >> color; cout<<"Apple's variety: "; cin >> variety; basket[i] = new Apple(weight, color, variety); } else { cout<<"Banana's weight: "; cin >> weight; cout<<"Banana's country: "; cin >> variety; basket[i] = new Banana(weight, variety); } } for(i = 0; i < num; i ++) { basket[i] ->print(); } for(i = 0; i < num; i ++) { delete basket[i]; }//调用Fruit析构内存泄露 return 0;}////////////////////////////////////End////////////////////////////////////
阅读全文(1102) | 回复(0) | 编辑 | 精华
|