c++中的常见泄漏(七)

 c++中的常见泄漏(七)

-------------------------------------------------------------------------- 
*整理:Zsm。
*时间:2011-4-19。
*出处:http://blog.csdn.net/Zsm0107
--------------------------------------------------------------------------

      关于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;   

  /*拷贝构造函数的参数是一个已经被释放的Point对象,因为运算符+重载函数返回的是指向自动变量temp的隐指针。这个变量在退出运算符重载函数时就调用了它的析构函数*/

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值