读书笔记_Effective_C++_条款二十八:避免返回handlers指向对象内部成分
举个例子:
class Student
{
private:
int ID;
string name;
public:
string& GetName()
{
return name;
}
};
这是一个学生的类,类里面有两个成员变量,一个是学生ID,用整数表示,另一个是姓名,用string表示。有一个公有的方法GetName(),获得学生的名字,根据条款20所说的,使用引用可以防止资源不必要地拷贝,那么在返回值这边就用string&。但现在问题来了,这个函数只是想返回学生的姓名,并不想用户对之进行修改,但返回引用却提供了这样的一个接口,如:
int main()
{
Student s;
s.GetName() = "Jerry";
cout << s.GetName() << endl;
}
就可以把名字进行修改。
你也许想到了,如果在前面加上const,像这样:
const string& GetName()
{
return name;
}
就可以阻止s.GetName() = “Jerry”这样的代码了。
但这样写还是存在问题,就是如果返回的引用生命周期比对象本身要长时,引用就会悬空,它会指向一个不存在的string。下面看一下“返回的引用生命周期比对象本身要长”的情况,这种情况还是很容易举出例子的,比如:
const string& fun()
{
return Student().GetName();
} int main()
{
string name = fun(); //name指向一个不存的对象的成员变量
}
这时候即使name读取不报错,也是一个巨大的隐患,因为它已经是虚吊(dangling)的了。
这就是为什么函数如果“返回一个handle代表对象内部成分”总是危险的原因,不在于返回值是不是const,而是在于如果handle(指针或引用)传出去了,就会暴露在“handle比其所指对象更长寿”的风险下。
但有些情况还是需要返回handle的,比如string或者vector里面的operator[],就是返回的引用,因为需要对这里面的元素进行操作。
好了,总结一下:
避免返回handles(包括reference、指针、迭代器)指向对象内部,遵守这个条款可增加封装性,并将发生dangling handles的可能性降至最低。如果有必要必须要返回handles,在编写代码时就一定要注意对象和传出handle的生命周期。
读书笔记_Effective_C++_条款二十八:避免返回handlers指向对象内部成分的更多相关文章
- 读书笔记_Effective_C++_条款二十九:为“异常安全”而努力是值得的
还是举书上的例子: void PrettyMenu::changeBackground(std::istream& imgSrc) { lock(&mutex); delete bgI ...
- 读书笔记_Effective_C++_条款四十八:了解模板元编程
作为模板部分的结束节,本条款谈到了模板元编程,元编程本质上就是将运行期的代价转移到编译期,它利用template编译生成C++源码,举下面阶乘例子: template <int N> st ...
- 读书笔记_Effective_C++_条款二十六:尽可能延后变量定义式的出现时间
这个条款从字面意思还是很好理解的,就是在使用这个变量前才去定义,而不是很早就定义了它,而在很后面的时候才去使用.这个条款只适用于对变量声明位置没有要求的语言,比如C++.对于像C或者一些脚本语言,语法 ...
- 读书笔记_Effective_C++_条款二十五: 考虑写出一个不抛出异常的swap函数
在之前的理论上调用对象的operator=是这样做的 void swap(A& x) { std::swap(a, x.a); } A& operator=(const A& ...
- 读书笔记_Effective_C++_条款二十四: 若所有参数皆需类型转换,请为此采用non-member函数
class A { private: int a; public: A(int x) :a(x){} A operator*(const A& x) { return A(a*x.a); } ...
- 读书笔记_Effective_C++_条款二十二:将成员变量声明为private
1.格式统一 在调用的时候,不会去想有没有(),一律是有get(),或者set()之类的. 2.封装 能直接访问得越少,表明封装性越高, 封装性越高,我们的顾虑就少了, 例如:我们a.data*0.9 ...
- 读书笔记_Effective_C++_条款三十八:通过复合塑模出has-a或者is-implemented-in-terms-of
如果说public是一种is-a的关系的话,那么复合就是has-a的关系.直观来说,复合就是在一个类中采用其他类的对象作为自身的成员变量,可以举个例子,像下面这样: class Person { pr ...
- 读书笔记_Effective_C++_条款三十:了解inline的里里外外
学过基本程序课的同学都知道,inline是内联的关键字,它可以建议编译器将函数的每一个调用都用函数本体替换.这是一种以空间换时间的做法.把每一次调用都用本体替换,无疑会使代码膨胀,但可以节省函数调用的 ...
- 读书笔记_Effective_C++_条款三十二:确定你的public继承继承塑模出is-a关系
这一条款是说的是公有继承的逻辑,如果使用继承,而且继承是公有继承的话,一定要确保子类是一种父类(is-a关系).这种逻辑可能与生活中的常理不相符,比如企鹅是生蛋的,所有企鹅是鸟类的一种,直观来看,我们 ...
随机推荐
- 关于parse_str变量覆盖分析
这个漏洞有两个姿势.一个是不存在的时候一个是存在的时候. 经过测试该漏洞只在php5.2中存在,其余均不存在. 倘若在parse_str函数使用的代码上方未将其定义那么即存在变量覆盖漏洞否则不行. 还 ...
- vsftpd 安装配置详细教程
linux下ftp软件不少,大致特点:<br /> wu-ftp:比较老牌,但针对它的攻击比较多,设置比较麻烦,但功能比较强大.<br /> vsftpd:功能强大,配置也比较 ...
- 二叉树的层序遍历(levelordertraverse)
数据结构关于二叉树的遍历还有一种层序遍历,按层次依次输出元素.最上层最先输出,同层中最左最先输出,使用队列这一结构来实现: int levelOrderTraverse(IDTree *pTree) ...
- [002] delete_duplication_of_linked_list
[Description] Given a unsort linked list, delete all the duplication from them, no temporary space p ...
- 73.Vivado使用误区与进阶——在Vivado中实现ECO功能
关于Tcl在Vivado中的应用文章从Tcl的基本语法和在Vivado中的应用展开,继上篇<用Tcl定制Vivado设计实现流程>介绍了如何扩展甚至是定制FPGA设计实现流程后,引出了一个 ...
- LAMP结合discuz论坛的配置
一.安装discuz ---->//download discuz; [root@localhost ~]# mkdir /data/www [root@localhost ~]# cd /da ...
- Python——文件打开模式辨析
版权声明:本文系原创,转载请注明出处及链接. Python中,open()函数打开文件时打开模式如r.r+ .w+.w.a.a+有何不同 r 只能读 r+ 可读可写,不会创建不存在的文件.如果直接写文 ...
- Web服务器处理动态程序三种方式及Apache配置
模块.CGI.FastCGI三种方式介绍 以PHP脚本为例: 模块方式是指Web服务器通过libphp5.so模块调用PHP服务,模块将相关函数嵌入Web服务请求处理流程,不需要额外解释器进程.注意, ...
- Effective C++笔记(四):设计与声明
参考:http://www.cnblogs.com/ronny/p/3747186.html 条款18:让接口容易被正确使用,不易被误用 1,好的接口很容易被正确使用,不容易被误用.你应该在你的所有接 ...
- vmware linux虚拟机连接ip设置
首先: 点击VMware 编辑->虚拟网络编辑器: 然后选中VMnet8的查看NAT设置: 上图第二步(记下红框中网关地址和子网掩码): 第三步(用于设置虚拟机地址范围): 接下来就是设置虚拟机 ...