Effective C++:条款28:避免返回 handles 指向对象内部成员

(一)

有时候为了让一个对象尽量小,可以把数据放在另外一个辅助的struct中,然后再让一个类去指向它。看下面的代码:

class Point {
public:
	Point(int x, int y);
	void setX(int newVal);
	void setY(int newVal);
};

struct RectData {
	Point ulhc;
	Point lrhc;
};

class Rectangle {
public:
	Point& upperLeft() const { return pData->ulhc; }
	Point& lowerRight() const { return pData->lrhc; }
private:
	std::tr1::shared_ptr<RcetData> pData;
};

这样的设计看上去很beautiful。但是却是错误的,实际上它是自相矛盾的,看下面的代码:

Point coord1(0, 0);
Point coord2(100, 100);
const Rectangle rec(coord1, coord2);
rec.upperleft().setX(50);

错误的理由:(1)upperLeft()跟lowerRight()这两个函数都是const的,所以客户不能修改Rectangle;

(2)两个函数都返回reference指向private内部数据,调用者于是可通过这些reference更改内部数据。

upperLeft的调用者能够使用被返回的引用来更改成员。但rec其实应该是不可变的(const)!

所以上面那种类的设计是错误的!!!

所以从这个例子中,我们可以得到以下的教训:

(1)成员变量的封装性会被引用破坏。

(2)如果const成员函数传出一个reference,后者所指的数据与对象自身有关联,而它又被存储于对象之外,那么这个函数的调用者可以修改那笔数据。

同样的道理,返回对象的引用、指针、迭代器都会造成这种局面,它们都是“句柄”。返回一个代表对象内部数据的句柄,会降低对象的封装。

(二)解决办法:

只要对这两个函数的返回类型加上const即可:

class Rectangle {
public:
	const Point& upperLeft() const { return pData->ulhc; }
	const Point& lowerRight() const { return pData->lrhc; }
private:
	std::tr1::shared_ptr<RcetData> pData;
};

有了这样的改变,客户就只能读取矩形的Points,但是不能涂写它们。

(三)

上面那种解决方法虽然确保了内部对象不会被修改。但是却可能导致dangling handles(空悬的号码牌):这种handles所指东西(的所属对象)不复存在。

这种“不复存在的对象”最常见的来源就是函数返回值。

class GUIObject {...};
const Rectangle boundingBox(const GUIObject& obj);

GUIObject* pgo;
const Point* pUpperLeft = &(boundingBox(*pgo).upperLeft());

你会发现(boundingBox(*pgo).upperLeft())这是一个point对象。但是当这一句执行完后,这个临时对象temp会被析构。这时,pUpperLeft会指向一个空的对象。也就出现了悬空现象。

因此,这就是为什么函数如果“返回一个handle代表对象内部成分“总是危险的原因。

请记住:

(1)避免返回handles指向对象的内部。遵守这个条款可增加封装性,帮助const成员函数更加像一个const,并将“虚号码牌“的可能性降低到最低。

Effective C++:条款28:避免返回 handles 指向对象内部成员

时间: 2024-10-12 05:12:29

Effective C++:条款28:避免返回 handles 指向对象内部成员的相关文章

Effective C++ 条款28 避免返回handles指向对象内部成分

1. 所谓的handles指的是引用,指针,迭代器(可能与windows的句柄有所区别),返回一个handles会导致提供给用户对象内部数据的间接访问,这降低了成员变量的封装性,例如: class Demo{ public: ... int* getPtr() const { return ptr; } private: ... int* ptr; } 这段代码语法正确,但是它违背了将getPtr设为const的初衷:从语法上来说ptr所指对象也属于Demo对象的一部分,但从语法上讲,由于编译器

[Effective C++ --028]避免返回handles指向对象内部成分

假设程序涉及矩形.每个矩形由其左上角和右下角表示.为了让Rectangle对象尽可能小,可能把定义矩形的点放在一个辅助的struct内再让Rectangle去指它: 1 class Point { // 得到坐标 2 public: 3 Point(int x, int y) {}; 4 void setX(int newVal) {}; 5 void setY(int newVal) {}; 6 }; 7 8 struct RectData 9 { 10 Point ulhc; 11 Poin

条款28:避免返回handles指向对象的内部成分。

首先看看下面这个例子: 1 class Point{ 2 public: 3 point(int x, int y); 4 ... 5 void setX(int newVal); 6 void setY(int newVal); 7 ... 8 }; 9 struct RectData{ 10 Point ulhc; //左上角 11 Point lrhc; //右下角 12 }; 13 class Rectangle{ 14 ... 15 private: 16 shared_ptr<Rec

Effective C++ 条款28

避免返回handles指向对象内部成分 本节作者讲述的知识核心是对于一个类来说,应该避免类返回自己内部的私有数据. 如下: class Point{ public: Point(int x, int y); -- void setX(int newVal); void setY(int newVal); -- }; struct RectData{ Point ulhc;//upper left-hand corner point lrhc;//lower right-hand corner }

Effective C++ Item 28 避免返回对象内部数据的引用或指针

本文为senlie原创.转载请保留此地址:http://blog.csdn.net/zhengsenlie Item 31 经验:避免返回handles(包含 references.指针.迭代器)指向对象内部.遵守这个条款可添加封装性, 帮助 const 成员函数的行为像个 const,并将发生"虚吊号码牌"(dangling handles)的可能性降至最低. 演示样例: class Point{ public: Point(int x, int y); //... void set

More Effective C++ 条款28 Smart Pointers(智能指针)

1. 智能指针(如标准库的auto_ptr,shared_ptr,weak_ptr,boost的scoped_ptr等)主要用于动态内存的管理,同时提供给用户与内置指针一样的使用方法,本条款主要涉及智能指针在构造与析构,复制和赋值,解引等方面的注意点,而非智能指针的实现细节. 2. 智能指针的构造,赋值,析构 智能指针的copy constructor,assignment operator,destructor对应于不同的观念而有不同的实现,主要有三种选择: 1).不允许对象的共享,在调用co

Effective C++ 条款21必须返回对象时,别妄想返回其reference

1. 虽然一般情况下传参使用const-by-reference-to-const比较好,但返回值有时必须是对象而不是引用: 当reference绑定到函数内创建的局部对象时,函数调用结束后引用绑定在一个不存在的对象; 当reference绑定到堆内存对象时,函数调用后比较容易忽略内存释放,特别对于以下表达式:w=x*y*z.如果operator*返回指向堆内存的引用,那没内存泄露是必然的; 当reference绑定到函数内部创建的static对象时,对于以下表达式if(a*b==c*d)由于返

《Effective C++》学习笔记——条款28

***************************************转载请注明出处:http://blog.csdn.net/lttree******************************************** 五.Implementations Rule 28:Avoid returning "handles" to object internals 规则 28:避免返回handles指向对象内部成分 假设我们的程序涉及矩形.每个矩形由其左上角和右下角表示.

effective c++条款26-31“class and function的实现”整理

一.类的实现面临的问题: 太快定义变量可能造成效率上的拖延:过度使用转型(casts)可能导致代码变慢又难维护,又招来微妙难解的错误:返回对象"内部数据之号码牌(handls)"可能会破坏封装并留给客户虚吊号码牌:为考虑异常带来的冲击则可能导致资源泄漏和数据败坏:过度热心地inlining可能引起代码膨胀:过度耦合则可能导致让人不满意的冗长建置时间. 二.条款26:尽可能延后变量定义式的出现时间 有些对象,你可能过早的定义它,而在代码执行的过程中发生了导常,造成了开始定义的对象并没有被