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

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

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

全栈程序员社区此处内容已经被作者隐藏,请输入验证码查看内容
验证码:
请关注本站微信公众号,回复“验证码”,获取验证码。在微信里搜索“全栈程序员社区”或者“www_javaforall_cn”或者微信扫描右侧二维码都可以关注本站微信公众号。

(一)

有时候为了让一个对象尽量小,能够把数据放在另外一个辅助的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,并将“虚号码牌“的可能性减少到最低。




版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/117932.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 「 运动控制 」“ADRC自抗扰控制技术”(Active Disturbance Rejection Control)研究

    「 运动控制 」“ADRC自抗扰控制技术”(Active Disturbance Rejection Control)研究近年来,虽然现代控制理论取得了一系列成果,但是在工业领域的应用并没有代替PID控制。这说明现代控制理论在实际应用的过程中受到一定的限制,控制理论与生产生活实际仍然存在一定的代沟。对此,韩京清总结为基于“模型论”的控制理论在解决问题时没有以生产生活中的不确定性作为重点,没有抓住生产生活实践中所切实需要的核心。韩京清先生针对生产生活实践中存在的问题潜心研究,积极探索,逐步分析PID理论与现代控…

    2022年5月18日
    31
  • 基于 msf 的免杀项目的一些工具「建议收藏」

    基于 msf 的免杀项目的一些工具「建议收藏」https://mp.weixin.qq.com/s/W7mBroOtVUdMHA7f07J_7Q转载自信安之路这两个月来持续的糜烂,乱七八糟的事,在今天lol完觉得不能再浪费时间来Orz,向大神们开始学习来0x02avet工具使用此工具当年在2017年黑帽大会上惊艳全场,使用kali下载:gitclonehttps://github.c…

    2022年8月20日
    5
  • spring整合mybatis步骤_spring整合了哪些框架

    spring整合mybatis步骤_spring整合了哪些框架配置redis.clients.jedis.JedisPool时报错如下:Causedby:org.springframework.beans.factory.BeanCreationException:Errorcreatingbeanwithname’jedisPool’definedinclasspathresource[beans.xml]:Couldnotresolvematchingconstructor(hint:specifyindex/typ.

    2025年9月13日
    9
  • 2021年职称计算机考试模块,2021年职称计算机考试模块photoshop基础试题4.doc「建议收藏」

    2021年职称计算机考试模块,2021年职称计算机考试模块photoshop基础试题4.doc「建议收藏」2021年职称计算机考试模块photoshop基础试题41..下列哪个是photoshop图象最基本的组成单元:A.节点B.色彩空间C.象素D.路径正确答案:C2.下面对矢量图和象素图描述正确的是:A.矢量图的基本组成单元是象素B.象素图的基本组成单元是锚点和路径C.AdobeIllustrator9图形软件能够生成矢量图D.Adobephotoshop6能够生成矢量图正…

    2022年5月11日
    33
  • 学习使用口令激活成功教程工具:hashcat、LC、SamInside

    学习使用口令激活成功教程工具:hashcat、LC、SamInside在学习使用口令激活成功教程工具之前,我们要先创建一个用户账号,原理是利用其哈希值进行激活成功教程。很关键的一点是,要在虚拟机里面创建用户!!!很关键的一点是,要在虚拟机里面创建用户!!!很关键的一点是,要在虚拟机里面创建用户!!!重要的事情一定要说三遍。在宿主机(我是win10系统)创建用户获取的hash值是假的,根本无法用于激活成功教程。我个人猜测,是由于宿主机存在某种保护机制,使得不让获取到真正的hash。因…

    2022年7月24日
    8
  • 选择排序——C语言代码

    选择排序——C语言代码介绍选择排序下面是我在网上找的示例图,便于更好地理解选择排序通过这个图我们明白K只是一个标记,它标记的是比较中小的数。我们第一轮我们可以找到所有数中最小的数,然后让它和处于第一位的数进行位置交换,第二轮比较时,第一轮找出的最小数不在参加比较,然后我们可以找出剩下数中最小的数,之后的每轮同理。下面大家看一下我的代码首先要明白for(j=i+1;j&lt;=9;j++) { if(a[k]&…

    2022年6月25日
    35

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号