天天看点

c++中的常见泄漏

 关于nonmodifying运算符重载的常见迷思

详细:

         1.概念:所谓nonmodifying运算符就是不改变操作数的值,并且计算结果是一个与操作同类型的对象的运算符。比如数学运算符:+,-,*,/,%.而关系运算符(bool类型)和赋值运算符(改变左边的操作数)则不是nonmodifying运算符。

      2.与nonmodifying运算符有关的主要问题是返回值。为了提高效率节省时间,决定用引用方式来返回运算结果,而不是返回值方式(隐式调用拷贝构造函数)。返回引用相关的临时变量时,会出现内存泄漏问题。(用引用方式返回局部变量是错误的----当函数退出时,与这个引用相关的内存也就退回了栈。从而使函数调用者得到一个指向无效的、没有分配到内存的对象)

例子:

#include<iostream>

#include<string>

using namespace std;

class Point

{

private:

 int x;

 int y;

 char *color;

public:

    Point(int =0 , int =0 , char * ="white");

    ~Point();

    Point(const Point&);

    void print();

    const Point& operator=(const Point&);

    const Point& operator+(const Point&); 

    //正确的是: const Point operator+(const Point&);   

};

Point::Point(int new_x , int new_y , char *col)

{

 x=new_x;

 y=new_y;

 color=new char[strlen(col)+1];

 strcpy(color,col);

}

Point::~Point()

{

 delete color;

}

Point::Point(const Point& rhs)

{

 x=rhs.x;

 y=rhs.y;

 color=new char[strlen(rhs.color)+1];

 strcpy(color,rhs.color);

}

const Point& Point::operator=(const Point& rhs)

{

 if(&rhs==this)

  return (*this);

 x=rhs.x;

 y=rhs.y;

 delete color;

 color=new char[strlen(rhs.color)+1];

 strcpy(color,rhs.color);

 return (*this);

}

//此函数返回一个指向临时Point对象的隐指针(一个引用),这个指针在函数退出时就被释放啦

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);  

      //waring:returning address of local variable or temporary

}

void Point::print()

{

 cout<<"I live at ( "

  <<x<<" , "<<y<<" ) and my color is :"

  <<color<<endl;

}

int main()

{

 Point p1(10,10,"Blue");

 Point p2(20,60,"Green");

 Point p3=p1+p2;  

 p3.print();

 return 0;

}

*------------------------------------------------------------------------

*解决问题的一种方法是:将临时的Point对象作为类的内部静态存储对象。内部 *静态对象不会在进入/退出函数的时候被创建/释放,它只是进入/退出作用域。*但是对于嵌套调用(比如:x+y+z)就会出现问题啦

*----------------------------------------------------------------------*

//修改代码如下:

const Point& Point::operator+(const Point& rhs)

{

 static Point temp;  

//注意内部静态存储对象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);  

}

*-------------------------------------------------------------------------

*还有一种思路是利用动态分配来解决,但是由于动态分配的临时变量的析构函

*数并没有自动的被调用,即它们没有被收回。此外得不到对象的地址,函数的

*调用者也不能显示的调用析构函数。

*-----------------------------------------------------------------------*

//代码如下:

const Point& Point::operator+(const Point& rhs)

{

 Point *temp=new Point;

 delete temp->color;

 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);  

}

*-------------------------------------------------------------------------

综上所述:

    nonmodifying运算符返回的必须是一个对象,而不是一个对象的引用。

 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); 

}

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Zsm0107/archive/2011/04/19/6333247.aspx

继续阅读