本站首页    管理页面    写新日志    退出

公告

You are all my reasons! 

桃李花林又一在

淫荡一日同风起,风骚直上九万里

仙子凌波微步罗衫飘忽十步一回头

我的最爱:网游,程序,文学

QQ:89636669


我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:一维空间
日志总数:163
评论数量:248
留言数量:33
访问次数:651803
建立时间:2007年10月24日




 [C++]C++内存泄露典例

dskongenius 发表于 2007/10/24 23:02:59

//泄漏一//类的构造函数与析构函数中未匹配地调用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) | 编辑 | 精华

 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.188 second(s), page refreshed 144767813 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号