C++的未来和指针

本文由 伯乐在线 - 周昌鸿 翻译自 Meeting C++。欢迎加入 技术翻译小组。转载请参见文章末尾处的要求。

上周Meeting C++2013结束后,我对C++思考了很多,有一些内容和指针有关。在C++ 11中只对指针进行了小量的更新(引入了nullptr),不过过去几年中,C++中指针的语义和用法却发生了很多变化。

首先,我们从指针的原始意义开始,C++11中简单如type* pt = nullptr; 这里的指针是C语言中的核心概念,指针并不是C++发明的,据我所知也不是C发明的。但是C规范中定义了指针,并给出了在C和C++中使用指针的指导。事实上,指针是一个变量,它存储的值是内存中的一个地址。如果你对指针进行解引用操作,就能访问指针指向的变量。指针实际上是一个基础变量,它不知道它所指向的值是否有效,也不能感知其指向的值是否无效。在C语言中,一个指针指向0,说明其不指向任何值,因此也不具有效的值。所有其他指针都应该指向内存中有意义的地址,但实际上,有些指针没有正确的初始化,或者干脆越出了应有的范围。

在C++11中,将指针正确初始化为0的方法是使用关键字nullptr。这让计算机知道该指针当前为空。另外,还有一种常用的方式是将0定义为NULL或者其他定义或声明。C++11中使用nullptr统一了这种方式。C++中还引入了引用,它看起来像是变量的别名,其优势是使用引用的时候必须先初始化,因此,在引用生命周期起始时需要指向一个有效地址。不过,引用也只是指针的解引用,所以,一旦其引用的变量作用范围结束,其引用也无效了,使用指针时,你可以将指针置为0,但是针对引用却不能这么做。

但是在C++11和在C++11标准之前,一些事情发生了变化,指针是语言的核心概念,但是你在现代化的C++代码和函数库中却很少看到它们。远在C++11之前,boost创建了一系列非常有用的智能指针类,针对指针进行了封装,对其核心机制通过操作符重载。智能指针本身不是一个指针,而是一个栈上的变量或对象成员。智能指针使用了RAII来解决指针的一些问题,这并不是指针的职责。当在椎中分配内存时,new返回了指向该部分内存的地址,所以每分配一块动态内存,就需要使用一个指针,相当于创建对象的一个操作句柄。但是指针仅仅是一个简单的变量,不知道变量的拥有关系,也不能自动释放堆上的内存空间。智能指针担当了这一角色,拥有指针并在变量超出作用域时自动管理其堆上的值。在栈上的值意味着,一旦相应的栈被销毁,其管理的堆上的值会被自动释放,即使是在发生异常的情况下。

过去的一些年,C++出现了一些不同风格的使用,从使用类的C及大量使用指针,到类似我想Widget和QT这样面向对象的框架。在过去5-10年中的形成的一种新样式被认为是现代C++,一种趋向尽力发掘语言本身扩展能力,并试图找到不同特性针对不同场合的应用。值得注意的是boost在这一趋势中起到了引领风范的C++框架。C++标准在设计其标准库时也借鉴了这一点。与此同时,值语义变得流行起来,并且与move语义成为未来C++一个关键点。来自Tony van Eerds在Meeting C++的一份备忘幻灯片引起了我对指针的思考。它有两列,一个代表引用语义,一个代表值语义,以及其朗朗上口的主题词:

哦,不!使用指针 vs 哦,不要使用指针!

所以,在C++11或者后续的C++14,使用值语义的趋势盖过了使用指针。指针在取后台还是工作着,不过在新的C++14中,new和delete都将不提倡直接使用,new被抽象化为make_shared/make_unique。其内部使用了new,但是返回一个智能指针。shared_ptr 和 unique_ptr都表现为值语义类型。智能指针同样在其作用域结束时使用delete释放内存。这让我思考,C++中的指针是不是都可以填充不同的“角色”,或者被替换掉。

继承和虚拟函数

指针一个非常重要的用途是在继承中使用指针来指向一系列拥有相同接口的类型值。我想用Shape例子来阐明这一点,这里有一个基类Shape,同时其含有一个虚拟函数叫area的方法。同时,它还有几个派生类叫Rectange,Cirecle和Triangle。现在,有一个指针容器(比如:std::vector<Shape*>)来容纳指向不同形状的对象指针,每个对象都有自己的计算面积方法。这是C++中最常用指针的方式,尤其是在面向对象时。现在,好消息是,这里同样支持使用智能指针,当其使用这些智能指针时,内部会进行访问指针。Boost中甚至还有一个指针容器,能在清空容器时自动释放其中的智能指针元素。

现在考虑虚函数调用(这虽然不和指针有直接联系),虚函数调用通常会有点点慢,同时也不容易编译器针对其进行优化。所以,如果其类型在运行时是可知的,就可以使用静态分发或者编译器多态性来正确调用相应的虚函数方法,而不是在运行时使用虚函数指针。作为一种模式被叫做CRTP,已经实现了这一方式。最近的研究显示,这在gcc4.8中可以提高性能。有趣的是,通常情况下使用gcc4.9,优化器可以针对动态分发进行更进一步的优化。还是让我们继续回到指针。

不确定指针

有时候指针被用于有一系列可选值作为参数或者返回不确定的函数中,通常都默认为0,用户可以选择传递一个有效的指针给该函数。或者在返回的情况下,函数返回一个空指针表示执行失败。对于错误情景,现代C++中常使用异常,但是在有些嵌入式平台上不能工作,因此,(返回0)在C++的一些场合中也是一个有效的使用方式。同样的,这里也可以使用智能指针,智能指针可以扮演指针的操作句柄。不过常常会导致堆上内存开销(使用堆),或者并没有替代不确定的角色。这需要使用一个可选值类型来代替,用于确定其存储的值是否有效。Boost库有一个boost::optional来表示可选值类型。因此,可以考虑在C++14中引入有一个类似的可选类型。所以,现在std::optional会被移入到技术预览版(TS)中,将来会变成C++14或者C++1y的一部分。

当前的标准库中已经使用了一些可选类型,比如std::set::insert会返回一个pair<iterator,bool>类型,其第二个参数表示请求值是否插入到set容器中。容器通常返回尾迭代器来表示无效,但是如果要求返还一个值时,这个角色过去通常都是用指针来表示,指针为0表示函数执行失败,因此这里的指针可以被可选类型替代:

1
2
3
4
5
optional<MyValue> ov = queryValue(42);
if(ov)
  cout << *ov;
else
  cerr << "value could not be retrieved";

因此,可选类型和智能指针类型替代了指针的一部分语义,填充了其角色。但是它们是值语义,并大部分都在栈上使用。

有效的指针

在写作我对C++指针用法的思考时,我主要关注于那些指针可以被其他(比如:智能指针和可选类型等)替换的场景,但是低估了实际上有些场景指针仍然有用。感谢来自reddit,email和社交媒体的一些反馈。

非拥有者指针就是这样一个例子,这里未来的几年还是需要使用指针。shard_ptr有对应的weak_ptr,但是unique_ptr没有对应的伙伴。这里就需要使用非拥有者原始指针。比如,在一个由父和子对象构成的树或者图中。但是,未来C++中会新增exempt_ptr来代替。

在处理函数中的传递的值时,指针还是具有用处的,Herb Sutter写了一篇非常好的文章:《GotW about this in May》。Eric Niebler 在他的Meeting C++会议的笔记中也谈及了,同时移动语义会影响你应该如何在函数中传递或者返回值。

Category

C++11

Input Arguments

 

small/POD/sink

pass by value

all others

pass by const ref

Output

return by value

Input/Output

non const ref / stateful Algorithm Object

这个表格来自 Eric Nieblers 的笔记, 请看幻灯片中的16/31 (建议你阅读所有的幻灯片)

Eric Niebler说过,在能使用移动语义时尽可能使用移动语义。一个可选参数为例,vector::emplace_back接收一个参数,当其只是将把元素移动到适当位置,这时你应得使用移动语义。一些输出参数返回一个值,编译器可以使用移动语义或者CopyEllision(拷贝去除)的优化技术。针对一些以对象为输入/输出参数,非常引用也是可选择性优化的,但是Eric在他的笔记中指出:对象算法的状态在构造函数中应使用槽参数。

在传递常量(非常量)引用时,指针可以做同样的事情,不过有些不同,你需要对指针测试其是否为空。我个人更喜欢在函数/方法或者构造函数时传递引用而不是指针。

指针计算

之前我提到过,从我个人的观点,指针只是一个普通的变量,其值指向一个地址,或者更精确地说,是其指向值得一个地址号码。这个地址号码可以被复制,你可以对其进行加或减法操作。这常常用于遍历数组或者计算两个指针的的距离,这在使用数组时很有用。这里对数组的便利其实就是迭代器,所以,在实际代码时,指针可以代替迭代器使用。但是,从我多年C++开发经验来看,我几乎没有用到针对指针的计算操作。而且在C++中,指针的计算已经有了非常好的抽象。我的观点是,理解指针计算是重要的,这有助于理解代码中指针的具体作用。

再见,指针?

理论上,C++可以不使用指针,但是由于指针是C/C++语言的核心概念,指针本身仍然会继续存在。但是它的角色会变更,在你使用C++时,你不再需要考虑指针。随着C++的继续发展,C++11和C++14朝着更抽象,对开发者更友好的方向发展。使用智能指针和可选类型,指针要么被封装从而更适用安全的值类型,要么完全被它们替代掉。

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

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

相关文章

Java魔法类:Unsafe应用解析

Unsafe是位于sun.misc包下的一个类&#xff0c;主要提供一些用于执行低级别、不安全操作的方法&#xff0c;如直接访问系统内存资源、自主管理内存资源等&#xff0c;这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。但由于Unsafe类使Java语言…

AMD迎接变革:加速OpenCL的未来

摘要&#xff1a;AMD在北京中关村皇冠假日酒店举办了以"迎接变革&#xff1a;加速进入OpenCL 的未来"为主题的技术培训。AMD Firepro显卡资深产品经理JC、OpenCL资深讲师陆教授、谢博士与大家探讨OpenCL技术将如何引领变革、铸造计算新纪元。 4月11日&#xff0c;AM…

JAVA中神奇的双刃剑--Unsafe

参考资料&#xff1a; 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Java魔法类&#xff1a;sun.misc.Unsafe在openjdk8下看Unsafe源码 Unsafe介绍 在Oracle的Jdk8无法获取到sun.misc…

让AMD在中国发声 APU14技术创新大会首次在华召开

今日&#xff0c;AMD一年一度的开发者峰会“APU2014”在北京拉开帷幕&#xff0c;这也是AMD首次在美国之外的城市举办该活动。AMD全球副总裁、大中华区董事总经理潘晓明表示&#xff0c;大中华区是AMD重要的战略区域&#xff0c;AMD希望通过本次活动在中国制造巨大的声音&#…

Python已成美国顶尖高校中最受欢迎的入门编程语言

在最近的一份调查中显示&#xff0c;美国top高校中&#xff0c;Python已经成为教授计算机科学入门课程方面最受欢迎的语言。其中Top10 CS系中有8所使用Python&#xff0c;Top39 CS系中有24所&#xff0c;在入门课程中教授Python&#xff0c;可见其实用性的认可度很高。在我写下…

源码阅读 AtomicInteger

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 AtomicInteger 原子整数 可以原子更新的int值。 用于原子递增计数器等应用程序中&#xff0c;不能用作java.lang.Integer的替换。 扩展…

A饭福利,AMD Mantle API获众多游戏开发商青睐!

摘要&#xff1a;Videocardz整理了一份2014年—2015年支持AMD Mantle游戏列表&#xff0c;并公布了游戏开发商及游戏引擎的名称。已发布且支持Mantle的游戏主要有《战地4》、《神偷4》、《植物大战僵尸&#xff1a;花园战争》以及《狙击精英3》这四款。 现如今&#xff0c;越来…

linux 安装 maven 、解决:bash: mvn: command not found

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1、安装 wget 命令: yum -y install wget 2、下载maven安装包 wget http://mirrors.cnnic.cn/apache/maven/maven-3/3.5.4/binaries/a…

软件工程师必学的9件事

本文是html5tricks原创翻译&#xff0c;转载请看清文末的转载要求&#xff0c;谢谢合作&#xff01; 三年前&#xff0c;我还在巴塞罗那的神经科学实验室工作&#xff0c;忙着研究脑电波、教授心理学上的认知系统课程。而今天&#xff0c;我以设计和写软件为生。 你或许会满头…

Linux 的 chmod 命令,对一个目录及其子目录所有文件添加权限

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 对一个目录及其子目录所有文件添加权限 命令&#xff1a; chmod 777 -R ./html 给予html目录下可读可写可操作权限。 或者 chmod -R…

Linux 下压缩与解压.zip 和 .rar

1)对于.ziplinux下提供了zip和unzip程序&#xff0c;zip是压缩程序&#xff0c;unzip是解压程序。它们的参数选项很多&#xff0c;可用命令zip -help和unzip -help查看&#xff0c;这里只做简单介绍&#xff0c;举例说明一下其用法&#xff1a;# zip test.zip test.jpg test.pn…

优秀的程序员VS糟糕的程序员

优秀的程序员和一般的程序员差别在哪里&#xff1f;怎么才能成为优秀的程序员&#xff1f;我们选择了这个职业就要把他做好&#xff01; 优秀的程序员&#xff1a; 1、逻辑能力很强&#xff0c;这也是解决问题的关键。 2、分析能力。可以很好的解决复杂问题。 3、事情做得专…

图解 Java 常用数据结构

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 最近在整理数据结构方面的知识, 系统化看了下Java中常用数据结构, 突发奇想用动画来绘制数据流转过程. 主要基于jdk8, 可能会有些特性与…

程序员生存定律--使人生永动的势能

程序员生存定律这系列的目录在这里&#xff1a;程序员生存定律--目录 喜欢从头瞄的&#xff0c;可以移步。 ------------------------------------------------------------------------------- 这篇说的是精神&#xff0c;比较务虚&#xff0c;不感兴趣的可以略过。 在国内有…

int 和 Integer 的区别

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1、Integer是int的包装类&#xff0c;int则是java的一种基本数据类型 2、Integer变量必须实例化后才能使用&#xff0c;而int变量不需要…

度量术语之二:应用类和开发类生产率(实际度量案例)

一个令人震惊的事实是连生产率这种常见度量数据都没有一个简单的定义。连我们日常经常用到的公式&#xff1a;生产率工作产品/工作量&#xff08;工作产品可以是代码行&#xff0c;功能点&#xff0c;也可以是任何可以计数的东西&#xff0c;比如文档页数&#xff09;都是错误的…

注解 @ModelAttribute 运用详细介绍

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。1.ModelAttribute注释方法   例子&#xff08;1&#xff09;&#xff0c;&#xff08;2&#xff09;&#xff0c;&#xff08;3&#x…

编程语言 IDE 对比

IDE是集成开发环境的英文缩写&#xff0c;所谓集成开发环境&#xff0c;就是将你在开发过程中所需要的工具或功能集成到了一起&#xff0c;比如代码编写、分析、编译、调试等功能&#xff0c;从而最大化地提高开发者的工作效率。每种编程语言都有一些特定的IDE&#xff0c;本文…

强制更新 maven 缓存

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 mvn dependency:purge-local-repository

程序员为什么那么难升职

一个有趣的现象是老程序员很难升职&#xff0c;如果你因为3K工资太低而要辞掉工作&#xff0c;你的上司宁可去外面找一个5K工资的新人&#xff0c;也不会来挽留你。那么程序员为什么那么难升职&#xff0c;这里总结了几点。你上司的问题你晋升困难&#xff0c;最大的主观原因在…