Item 28:不要返回对象内部的句柄 Effective C++笔记
来源:互联网 发布:信息系统网络架构图 编辑:程序博客网 时间:2024/05/21 12:49
Item 28: Avoid returning "handles" to object internals.
不要返回对象私有成员的句柄。这里的“句柄”(handle)包括引用、指针和迭代器。 这样可以增加类的封装性、使得const
函数更加const
, 也避免了空引用的创建(dangling handles)。
为了方便起见,下文中统一用指针来称呼这三类句柄。
返回私有成员的指针
在继续Scott Meyers的讨论之前,先来回顾一下类成员指针的行为。 首先如果不加限制,直接返回私有成员的指针会导致私有成员被完全暴露。例如:
class Rectangle { int _left, _top;public: int& left() { return _left; }};Rectangle rec;rec.left() = 3; // rec._left被修改
其实这已经足以说明返回私有成员指针相当于完全暴露了私有成员。
暴露私有成员为常量
如果是为了保护私有成员不被修改,只是为了让外界可以不通过函数就可以访问_left
, 可以将left()
声明为const
:
int& left() const{ return _left; }
上述代码还有问题~ 编译器会产生如下错误:
error: binding of reference to type 'int' to a value of type 'const int' drops qualifiers
这是因为常量方法不能修改当前对象,其返回值也应该是const
的。应该这样写:
const int& left() const{ return _left; }
由于返回值声明了const
,客户修改内部变量便会编译错了。我们成功地在开放了内部变量的同时防止了内部变量被修改。但是问题没有到此为止!还记得吗?C++的常量定义为"bitwise constness",只要当前对象没被修改就算常量。所以如果我们将left
和top
存在类的外面,常量方法的返回值类型检查便会失效,比如把数据存在Point
里面:
class Point{public: int left, right;};class Rectangle { Point* p;public: int& left() const { return p->left; }};...const Rectangle rec;rec.left() = 3; // rec明明是const对象,但我们可以修改它~
现在Rectangle
的大小是sizeof(void*)
(指针大小), 即p->left
并不在这个对象的内存里, 因而常量方法的返回值可以不声明const
。 这时客户便可以通过这个返回的left
来修改对象私有成员了。 所以返回对象内部的指针,会导致常量方法的const
属性被破坏。 根本原因在于C++的"bitwise constness"语法检查风格。
注意如果
p
被声明为Point
而非Point*
时,p->left
仍处于当前类的内存区域内, 编译器会要求left() const
返回值为const int&
。
空悬指针问题
可能你已经注意到了,我们完全可以稍微改善一下上面的代码来实现私有成员的写保护。 既然是由于"bitwise constness"编译器不提供类型检查, 我们手动限制返回值为const
即可:
const int& left() const{ return p->left; }
很多情况下问题确实是这样解决的,比如实现operator[]() const
时。 但下标运算符只是一个特例,一般情况我们是不会返回内部指针的。 因为返回的指针和拥有者对象具有同样的生命周期, 返回的指针很容易被悬空,比如有一个返回Rectangle
的bounding
函数:
const Rectangle bounding();
我们希望获得那个Rectangle
的left
,可能会这样写:
const int& left = bounding().left();
问题在哪里呢?left
被悬空了,它并没有保持left
的值! 因为bounding()
返回的对象没有赋值给任何变量它是一个临时对象。 临时对象在语句执行后立即销毁,那个私有成员的引用也将失效。
除非注明,本博客文章均为原创,转载请以链接形式标明本文地址: http://harttle.com/2015/08/26/effective-cpp-28.html
- Item 28:不要返回对象内部的句柄 Effective C++笔记
- Effective c++ Item 28 不要返回指向对象内部数据(internals)的句柄(handles)
- Effective c++ Item 28 不要返回指向对象内部数据(internals)的句柄(handles)
- Effective c++ Item 28 不要返回指向对象内部数据(internals)的句柄(handles)
- Effective c++之Item 28: 避免返回对象内部构件的“句柄”
- [翻译] Effective C++, 3rd Edition, Item 28: 避免返回 object 内部构件的 "handles"(“句柄”)
- Effective C++ Item 28 避免返回对象内部数据的引用或指针
- Item 21:需要返回对象时,不要返回引用 Effective C++笔记
- 《Effective C++》学习笔记条款28 避免返回handls指向对象内部成分
- effective C++笔记之条款29: 避免返回内部数据的句柄
- 避免返回对象内部构件的“句柄”
- 《Effective C#》Item 22:避免返回类内部成员的引用
- 读书笔记 effective c++ Item 21 当你必须返回一个对象的时候,不要尝试返回引用
- 读书笔记 effective c++ Item 21 当你必须返回一个对象的时候,不要尝试返回引用
- effective C++笔记之条款31、32: 千万不要返回局部对象的引用,也不要返回函数内部用new初始化的指针所指对象的引用、尽可能地推迟变量的定义
- Effective Item 21: 当你必须返回一个对象时不要试图返回一个引用
- 条款31: 千万不要返回局部对象的引用,也不要返回函数内部用new初始化的指针的引用 (转自effective c++ second edition)
- Effective C++ 条款31: 千万不要返回局部对象的引用,也不要返回函数内部用new初始化的指针的引用
- 各种编程语言的深度学习库整理
- Android EditText和TextView图文混排
- typedef和#define的区别
- 让你彻底弄清offset
- IOS巅峰之归档与反归档
- Item 28:不要返回对象内部的句柄 Effective C++笔记
- SVN分支的合并和同步
- hdu1829
- String,StringBuffer,StringBuilder黑马精华贴
- Eclipse中安装SVN插件方法
- 《数据结构与算法分析》寻找欧拉回路--多次修改最终复杂度O(E+V)
- 前端注意事项总结
- iOS 蓝牙4.0(BLE)后台或者锁屏也可以接收数据的方法
- TCL第三代黑水晶超薄电视C1上市 缔造业界新高度