C++ 避免返回handles指向对象内部成分

20180316 C++ 避免返回handles指向对象内部成分

假设你的程序涉及矩阵。每个矩阵由其左上角和右下角表示,为了让一个矩阵(Rectangle)对象尽可能小,你可能会决定不把定义矩阵的这些点存放在矩阵(Rectangle)对象内,而是放在一个辅助是结构体(struct)内再让矩阵(Rectangle)去指向它:
class Point{//这个class用来表示“点”
  public:
    Point(int x,int y);
    ...
    void setX(int newVal);
    void setY(int newVal);
    ...
};


struct RectData{//这些点数据用来表现一个矩阵
  Point ulhc;  //ulhc = "upper left-hand corner" 即左上角
  Point lrhc;  //lrhc = "lower right-hand corner" 即右下角
};


class Rectangle{
  ...
private:
  std::tr1::shared_ptr<RectData> pData;    
}


矩阵的客户必须能够计算矩阵的范围,所以这个类提供upperLeft函数和lowRight函数,Point是个用户自定义类型,因为以by reference方式传递用户自定义类型往往比以by value方式传递更高效,所以这些函数返回references,代表底层的Point对象:
class Rectangle{
public:
  ...
  Point upperLeft() const {return pData->ulhc;}
  Point lowRight() const {return pData->lrhc;}
}
这样的设计可通过编译,但确实错误的,实际上它是自我矛盾的,一方面upperLeft和lowRight被声明为const成员函数,因为他们的目的只是为了提供客户一个得知Rectangle相关坐标点的方法,而不是让客户修改Rectangle。另一方面两个函数却都返回reference指向private内部数据,调用者于是可通过这些reference更改内部数据。例如:
Point coord1(0,0);
Point coord2(100,100);
const Rectangle rec(coord1,coord2);
/*rec是个const矩阵,从(0,0)到(100,100)*/




rec.upperLeft().sexX(50);
/*现在rec却变成从(50,0)到(100,100)*/


这里请注意,upperLeft的调用者能够使用被返回的reference(指向rec内部的Point成员变量)来更改成员。但rec其实应该是不可变的(const)。


上面所发生的事是由于“成员函数返回reference”。若他们返回的是指针或迭代器,相同的情况还是发生,原因也相同。


当我们把注意力集中于Rectangle class和他的upperLeft以及lowerRight成员函数。我们在这些函数身上遭遇的两个问题就可以轻松去除,只要对它们的返回类型加上const即可:
class Rectangle{
public:
  ...
  const Point& upperLeft() const {return pData->ulhc;}
  const Point& lowerRight() const {return pData->lrhc;}
  ...
}
有了这样的改变,客户可以读取矩阵的Point,但不能涂改它们。但即使如此,upperLeft和lowerRight还是返回了“代表对象内部”的handles,有可能在其他场合带来问题,更明确的说,他可能导致空悬的号码牌(dangling handles):这种handles所指的东西(的所属对象)不复存在。这种“不复存在的对象”最常见的来源就是函数返回值。


这并不意味着你绝对不可以让成员函数返回handles。有时候你必须那样做。例如operator[]就允许你"采摘"strings和vectors的个别元素,而这些operator[]s就是返回references指向“容器内的数据”,那些数据会随着容器被销毁而销毁。尽管如此,这样的函数毕竟是例外,不是常态。


注意:避免返回handles(包括reference、指针、迭代器)指向对象内部。遵守这个条款可增加封装性,帮助const成员函数的行为像个const,并将发生“虚吊号码牌”(dangling handles)的可能性将至最低。
















































































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值