Chinaunix首页 | 论坛 | 博客
  • 博客访问: 93343
  • 博文数量: 38
  • 博客积分: 950
  • 博客等级: 准尉
  • 技术积分: 235
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-01 10:17
文章分类
文章存档

2011年(38)

我的朋友

分类: LINUX

2011-05-17 00:31:44

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

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


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

例子:
#include
#include
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 ( "
  <  <}
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);  
}

阅读(555) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~