Avoid returning "handles" to object internals
动机
先来看一个例子: 1
2
3
4
5
6
7
8
9
10
11
12
13
14class Point{...};
struct RectData{
Point ulhc;
Point lrhc;
};
class Rectangle{
private:
std::trl::shared_ptr<RectData> pData;
public:
Point& upperLeft() const{return pData->ulhc;}
Point& lowerRight() const {return pData->lhrc;}
};
使用: 1
2const Rectangle rec(point1, point2);
rec.upperLeft().setX(50);
其实,这样使用编译器是不会报错的,但其出现了矛盾的情况,原因是我们在该函数后面指定了const,则希望rec是不变的。但我们可以看到,由于我们返回的是一个引用,则可以通过引用去修改对象内部的成员。
同理,返回指针或者迭代器这些handles,也会出现这种情况。
解决方法
为了解决这个问题,我们可以这样: 1
2
3
4
5class Rectangle{
...
const Point& upperLeft() const{return pData->ulhc;}
const Point& lowerRight() const {return pData->lhrc;}
};
但这种用法同样会有一些问题,那就是有可能会出现dangling
handles。 1
2
3
4
5
6class GUIObj{...};
const Rectangle boudingBox(const GUIObj& obj);
GUIObj* obj;
...
const Point* p = &(boudingBox(*p).upperLeft());
这是因为返回一个handle代表对象内部成员的话,不管这个handle是指针还是引用,也不管是不是const,这里的关键是一旦这个handle传出去了,你就得承受一个风险——handle可能会比其所指向的对象有着更长的声明周期。
建议
- 避免返回任何handles指向对象的内部。另外,还要使得const成员函数的行为像个const,并且尽量避免发生dangling handles。