vb 根据pid获取句柄_C++中避免返回指向对象内部的句柄(handles)

b18bbf08c2182ee42f92a68b4e963cd3.gif点蓝色字关注“CurryCoder的程序人生”

微信公众号:CurryCoder的程序人生
欢迎关注我,一起学习,一起进步!

04d3f5f825a52f0d716b5110398b9df2.png


1.问题的引入

假如你正在给一个应用写一个矩形类,这个矩形由左上角和右下角的顶点坐标表示。为了表示这两个点,我们写一个表示点的类:
class Point{
public:
    Point(int x, int y);
    void setX(int newVal);
    void setY(int newVal);
    // ....
};
为了让矩形对象的体积小一点,我们将这两个顶点装在另一个结构体中,并用指针指向它:
struct RectData{
    Point ulhc;  // 左上角
    Point lrhc;  // 右下角
};

class Rectangle{
    // ...
private:
    std::shared_ptr pData;  
};
由于用户想要得到点的坐标,所以需要让矩形类要提供返回这两个点的函数。因为矩形类是我们自定义的类,根据之前的文章C++中多用引用传递方式替换值传递方式中提到的对于自定义的类,传递引用方式比传值方式更高效,所以我们让这两个函数返回引用:
class Rectangle{
public:
    // ...
    Point& upperLeft() const {
        return pData->ulhc;
    }

    Point& lowerRight() const {
        return pData->lrhc;
    }
private:
    std::shared_ptr pData;  
};
上面的代码虽然可以通过编译,但却是自我矛盾的!首先,函数upperLeft()和函数lowerRight()被声明为const成员函数。因为它们的目的是为了只返回一个对象而别的什么都不做,但两个函数却都返回了指向私有成员的引用,因此调用者就能通过这个引用来改变对象。
Point coord1(0, 0);
Point coord2(100, 100);
const Rectangle rec(coord1, coord2);  // 我们希望它是常对象rec
rec.upperLeft().setX(50);  // upperLeft()的调用者rec能够使用被返回的指向rec内部的Point成员变量的引用来更改成员
// 但是,rec实际上是不可变的,因为它是常对象
2.得到的结论从上面的代码段中,我们可以得到下面两个教训:(1).数据成员的最好封装性取决于最能破坏封装的函数。虽然ulhc和lrhc两个点都声明为private,但由于存在两个返回引用的函数的存在,它们其实相当于是public。因为public函数upperLeft()和lowerLeft()传出了它们的引用。(2).如果一个函数返回了指向储存在对象外部的数据成员的引用,即使这个函数声明为了const,这个函数的调用者也能修改这个成员。原因见之前的文章尽可能使用const修饰符中的bitwise constness的局限性除了引用,返回指针和迭代器也是相同的结果,也是由于相同的原因导致。引用、指针、迭代器都是本文标题中所说的"句柄"(handle),即接触对象的某种方式。直接返回句柄总会带来破坏封装的风险,这也导致声明为const的函数并不是真正的const。注意:"内部成员"除了内部数据还包括内部函数,即声明为私有(private)或保护(protected)的函数。因此,对于内部函数也是一样,也不要返回它们的句柄,否则用户也可以通过返回的函数指针来调用它们,这样私有的成员函数也相当于变成了公有。

3.问题的解决方法

回到上面出现自我矛盾的代码段,如果要解决返回引用会导致数据成员被改变的问题,只需要给函数的返回类型加上一个const。如下面的代码段所示:
class Rectangle{
public:
    // ...

    // 现在返回的是const Point&  
    const Point& upperLeft(){
        return pData->ulhc;
    }

    const Point& lowerRight(){
        return pData->lrhc;
    }
private:
    std::shared_ptr pData;  
};
这样用户就只能对其进行读操作而不能进行写操作了,给函数声明的const也就不会骗人了。至于封装性问题,让用户知道这个矩形的位置是完全合情合理的,所以我们给封装提供了有限的放宽,让用户可以读到私有数据,但坚决不能让用户执行写操作。然而即使这样,返回的句柄仍然会导致一个问题:"野句柄"(dangling handle),即这个句柄指向的对象不存在。最常见的场景是函数返回值,假如我们正在给某个GUI对象写一个返回它边界框的函数,返回类型是Rectangle。如下面的代码段所示:
class GUIObject{
    // ...
};

const Rectangle boundingBox(const GUIObject& obj);
现在,客户可能会像下面那样使用这个函数:
GUIObject* pgo;
// ...
const Point* pUpperLeft = &(boundingBox(*pgo).upperLeft());
现在有意思的事发生了,取址运算符括号里面的函数boundingBox()会返回一个新的临时Rectangle对象称为temp。有了这个临时对象之后,我们就可以获得指向它左上角的Point对象,然后pUpperLeft自然就获得了这个Point对象的地址。但是,temp毕竟是临时对象。在这行代码执行完后,temp会被销毁,它所包含的Point对象也会被销毁。最后,pUpperLeft存储了一个指向不存在的对象的指针。因此,这也解释了为什么返回指向内部成员"句柄"的函数是危险的,不管你的"句柄"是指针、引用还是迭代器;不管你的函数返回值是不是const、你的函数是不是const。但是,这不代表要杜绝这种做法,有时候不得不这样做。例如索引[]操作符,用来获取容器(比如std::vector)中的某个对象,它返回的是指向容器中的数据的引用,来让你完成写操作。记住,在我们自己设计的程序中还是尽量避免不要这么做。

4.总结

(1) 避免返回指向内部成员的"句柄"(包括指针,引用,迭代器)。不返回"句柄"能增强封装性,让const函数成为真正的const,也能减少"野句柄"。

觉得好看,请点这里↓

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/470306.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于MapReduce中自定义Combine类(一)

MRJobConfigpublic static fina COMBINE_CLASS_ATTR属性COMBINE_CLASS_ATTR "mapreduce.job.combine.class"————子接口(F4) JobContent方法getCombinerClass————子实现类 JobContextImpl实现getCombinerClass方法:public C…

react脚手架配置代理解决跨域问题

一、问题描述: 控制台报错,出现跨域问题 二、解决方案 配置代理: 第一种配置方式: 在package.json中追加如下配置 "proxy":"http://localhost:5000"说明: 优点:配置简单&#xff…

kstools工具是什么牌子_2020年平衡车推荐,电动平衡车哪个牌子好?老司机教你如何选购电动平衡车...

2020年平衡车推荐,电动平衡车哪个牌子好?老司机教你如何选购电动平衡车随着我国科技的发展,生活水平的提高,在很多地方都出现了电动平衡车的身影,人们将电动平衡车当做短距离代步的工具,也是非常实用的。很…

plsql 中的一些好的设置和快捷键总结

1、SQL语句字符全部大写 自认为这是个好习惯,信息系统的核心是数据库,系统出问题时最先要查的就是SQL语句,怎样在浩瀚的日志中快速找到那条SQL语句是件比较痛苦的事情。 SQL语句全部大写并不能彻底解决这一问题,但在一堆代码…

react父子组件通信案例

父组件:App组件 子组件:Search组件、List组件 案例需求:文本框中输入关键词,点击搜索按钮后,下方列表展示出搜索结果 实现思路: 子组件Search组件向父组件App传递状态(状态包括:是否…

matlab画线不同颜色_怎样画线框图才有意义

我们常轻忽身边习以为常的事物,觉得没有必要为一些看似简单又可有可无的东西浪费时间——例如线框图。虽然没必要凡事都寻根问底,但当面对复杂问题时,脚踏实地回归基本面也许才是根本解法。本文章深入介绍程序开发界面设计中,最简…

react 消息订阅-发布机制(解决兄弟组件通信问题)

消息订阅-发布机制 工具库: PubSubJS下载: npm install pubsub-js --save使用: 1)import PubSub from ‘pubsub-js’ //引入 2)PubSub.subscribe(‘delete’, function(data){ }); //订阅 3)PubSub.publish(‘delete’, data) //发布消息 App组件: import React,…

运行Myeclipse发生这事这是怎么回事,大神们

转载于:https://www.cnblogs.com/zhuh102/p/5753616.html

非零返回怎么解决_VLOOKUP如何返回多个值?

今天我来谈谈大家最熟悉的函数,也是使用频率最高的函数,基本是每天都在使用-VLOOKUP大家都知道VLOOKUP可以根据条件,查找并返回满足条件对应列的值,但是他的设定只是只能返回第一个满足条件的值如果我们要返回满足条件的多个值&am…

Fetch发送网络请求

1. 文档 https://github.github.io/fetch/https://segmentfault.com/a/1190000003810652 2. 特点 fetch: 原生函数,不再使用XmlHttpRequest对象提交ajax请求老版本浏览器可能不支持 3. 相关API GET请求 fetch(url).then(function(response) {return response.…

JSX详解React的事件绑定事件参数的传递

一、认识JSX 这段element变量的声明右侧赋值的标签语法是什么呢? 它不是一段字符串(因为没有使用引号包裹),它看起来是一段HTML原生,但是我们能在js中直接给一个变量赋值html吗?其实是不可以的&#xff0c…

总谐波失真计算公式_新能源汽车技术|车用轮毂电机转矩谐波协同控制策略

点击 电机与控制应用 关注我们轮毂电机因结构简单、驱动灵活的特点广泛应用于轻型电动车辆。电机运行中存在的齿槽效应、逆变器非线性效应及电流谐波等问题,导致电机电磁转矩波动,影响车辆运行的平顺性。通过电磁转矩谐波分析发现其主要成分为低阶谐波。…

React条件渲染列表渲染

一、React条件渲染 某些情况下,界面的内容会根据不同的情况显示不同的内容,或者决定是否渲染某部分内容: 在vue中,我们会通过指令来控制:比如v-if、v-show;在React中,所有的条件判断都和普通的J…

解决VirtualBox错误:“FATAL:No bootable medium found!”

VirtualBox错误:“FATAL:No bootable medium found!”  用VirtualBox安装系统出现这个错误的几率极高,因为当哥出现同样问题的时候股沟了下”FATAL:No bootable medium found!“出现很多内容,但没一个把问题解决了的…

React事件总线

通过Context主要实现的是数据的共享,但是在开发中如果有跨组件之间的事件传递,应该如何操作呢? 一、安装events 在Vue中我们可以通过Vue的实例,快速实现一个事件总线(EventBus),来完成操作&…

React中使用ref

一、如何使用ref 在React的开发模式中,通常情况下不需要、也不建议直接操作DOM原生,但是某些特殊的情况,确实需要获取到DOM进行某些操作: 管理焦点,文本选择或媒体播放;触发强制动画;集成第三方…

React中的受控组件和非受控组件

一、认识受控组件 在React中,HTML表单的处理方式和普通的DOM元素不太一样:表单元素通常会保存在一些内部的state。 比如下面的HTML表单元素: 这个处理方式是DOM默认处理HTML表单的行为,在用户点击提交时会提交到某个服务器中&…

JS动画 | 用TweenMax实现收集水滴效果

之前在CodePen上接触了TweenMax, 被它能做到的酷炫效果震撼了. (文末放了5个GSAP的效果GIF) 最近要做一个"收集水滴"的动效, 于是就试用了一下TweenMax实现这个效果. 什么是TweenMax TweenMax是GSAP(GreenSock Animation Platform)创作的动画工具库. GSAP的产品除了T…

React中的组件通信——父传子、子传父、Context

0、认识组件间的通信 在开发过程中,我们会经常遇到需要组件之间相互进行通信: 比如App可能使用了多个Header,每个地方的Header展示的内容不同,那么我们就需要使用者传递给Header一些数据,让其进行展示;又比…

React ref的转发

在前面学习ref时讲过,ref不能应用于函数式组件: 因为函数式组件没有实例,所以不能获取到对应的组件对象 但是,在开发中我们可能想要获取函数式组件中某个元素的DOM,这个时候我们应该如何操作呢? 方式一&…