C++ 11和C++98相比有哪些新特性

C++版本发展简史:新特性介绍 阅读详情

C++ 11和C++98相比有哪些新特性

目录

 

正文

 此文是如下博文的翻译:

https://herbsutter.com/elements-of-modern-c-style/

 

 

C++11标准提供了许多有用的新特性。这篇文章特别针对使C++11和C++98相比看上去像一门新语言的特性,因为:

  • C++11的这些特性改变了书写C++代码的风格和习惯,也改变了设计C++库的方式。例如,你会看到更多的被当作参数和返回值的智能指针,还有按值(by value)返回超大对象的函数。
  • 它们被使用的非常广泛,在大多数代码中你都能看到它们。举个例子,在现代C++中几乎每5行C++代码你就能看到auto关键字。

还有一些其它的非常好的C++11新特性,但先把这篇文章所描述的新特性熟悉起来把,因为这些被广泛使用的特性展示了为什么C++11代码是简洁的,安全的和快速的,就像其它现代主流开发语言一样,并且性能和传统C++一样强大。

回到顶部

1. Auto

在任何可能的时候使用auto。因为有两个原因。第一,非常明显,能够避免重复输入我们已经声明的并且编译器已经认识的类型名称,这是非常方便的。

复制代码

 1 // C++98
 2 
 3 map<int,string>::iterator i = m.begin();
 4 
 5 double const xlimit = config["xlimit"];
 6 
 7 singleton& s = singleton::instance(); 
 8 
 9 // C++11
10 
11 auto i = begin(m);
12 
13 auto const xlimit = config["xlimit"];
14 
15 auto& s = singleton::instance();

复制代码

 

第二,当有遇到一个你不知道或者无法用语言表达的类型时,auto就不仅仅是使用方便这么简单了,比如,大多数lambda函数的类型,你不能够容易的将其类型拼写出来甚至根本就不能够写出来。

复制代码

// C++98

binder2nd< greater > x = bind2nd( greater(), 42 ); 

// C++11

auto x = [](int i) { return i > 42; };

复制代码

 

注意,使用auto并没有修改代码的语义。代码仍然是静态类型(statically typed),并且每个表达式都干净利落;只是不再强制我们多余的重新声明类型的名称。

一些人开始的时候害怕使用auto,因为给人的感觉像是并没有声明(重新声明)我们想要的类型,这意味着我们可能会突然得到一个不同的类型。如果你想显示的做强制类型转换,这没有问题;声明目标类型就可以了。但是在大部分情况下,使用auto就足够了,由于出现错误而得到另外一个类型的情况很少见,在使用强静态类型(strong static typing)情况下,如果类型出现错误编译器就会告诉你。

回到顶部

2. 智能指针,no delete

总是使用智能指针,不要用原生指针和delete。除非需要实现你自己的底层数据结构(把原生指针很好的封装在类(class boundary)中

如果你知道你是另外一个对象的唯一拥有着,使用unique_ptr来表示唯一的拥有权。一个"new T"表达式能很快的初始化一个拥有 这个智能指针的对象,特别是unique_ptr。典型的例子是指向实现的指针(Pimpl Idiom):

复制代码

 1 // C++11 Pimpl idiom: header file
 2 class widget {
 3 public:
 4     widget();
 5     // ... (see GotW #100) ...
 6 private:
 7     class impl;
 8     unique_ptr<impl> pimpl;
 9 };
10  
11 // implementation file
12 class widget::impl { /*...*/ };
13  
14 widget::widget() : pimpl{ new impl{ /*...*/ } } { }
15 // ...

复制代码

 

使用shared_ptr来表示共享所有权(shared ownership)。使用make_shared来创建共享对象更好。

复制代码

1 // C++98
2 widget* pw = new widget();
3 :::
4 delete pw;
5  
6 // C++11
7 auto pw = make_shared<widget>();

复制代码

 



使用weak_ptr来打破循环和表示可选性(比如实现一个对象缓存)

复制代码

 1 // C++11
 2 class gadget;
 3  
 4 class widget {
 5 private:
 6     shared_ptr<gadget> g; // if shared ownership
 7 };
 8  
 9 class gadget {
10 private:
11     weak_ptr<widget> w;
12 };

复制代码

 


如果你了解到另外一个对象比你的生存周期要长,并且你想观察这个对象,那么使用原生指针(raw pointer)。

复制代码

1 // C++11
2 class node {
3  vector<unique_ptr<node>> children;
4  node* parent;
5 public:
6  :::
7 };

复制代码

 

回到顶部

3. Nullptr


用nullptr来表示一个空指针,不要再使用数字0或者宏NULL来表示空指针了,因为这些是模棱两可的,既能表示整形也可表示指针。

1 // C++98
2 int* p = 0;
3  
4 // C++11
5 int* p = nullptr;

 

回到顶部

4. Range for


对一个范围内的元素进行有序访问,基于range的for循环会是更方便的用法。

复制代码

1 // C++98
2 for( vector<int>::iterator i = v.begin(); i != v.end(); ++i ) {
3     total += *i;
4 }
5  
6 // C++11
7 for( auto d : v ) {
8     total += d;
9 }

复制代码

 

回到顶部

5. 非成员begin和end


使用非成员函数begin(x)和end(x)(不是x.begin()和x.end()),因为begin(x)和end(x)是可扩展的,能同所有容器类型一块工作——甚至数组也可以——并不是只针对提供了STL风格的x.begin()和x.end()成员函数的容器。
如果你正在使用一个非STL集合类型,这个类型提供迭代器但不是STL风格的x.begin()和x.end(),你可以对他的非成员函数begin()和end()进行重载,这样你就可以使用同STL容器同样的风格进行编码。标准中举了一个例子:数组,并且提供了对象的begin和end函数:

复制代码

 1 vector<int> v;
 2 int a[100];
 3  
 4 // C++98
 5 sort( v.begin(), v.end() );
 6 sort( &a[0], &a[0] + sizeof(a)/sizeof(a[0]) );
 7  
 8 // C++11
 9 sort( begin(v), end(v) );
10 sort( begin(a), end(a) );

复制代码

 

回到顶部

6. Lambda函数和算法

Lambda表达式改变了游戏规则,它会时不时的改变你的编码方式,这种方式优雅并且快速。Lambda使现存STL算法实用性提高了百倍。
新增加的C++库的设计都以支持lambad表达式为前提(例如:PPL),甚至有一些库需要通过你编写lambda表达式来它(例如:c++ AMP)。
这里有个例子,找到v中的>X并且<Y的第一个元素。在C++11中,最简单并且干净的代码是使用标准算法。

复制代码

1 // C++98: write a naked loop (using std::find_if is impractically difficult)
2 vector<int>::iterator i = v.begin(); // because we need to use i later
3 for( ; i != v.end(); ++i ) {
4     if( *i > x && *i < y ) break;
5 }
6  
7 // C++11: use std::find_if
8 auto i = find_if( begin(v), end(v), [=](int i) { return i > x && i < y; } );

复制代码

 

想使用一个循环或者类似的语言特性(language feature)但实际上在该语言中并不存在,怎么办?将其实现成模板函数(库算法)就可以了,多亏了lambda,使用它就像是用一个语言特性一样的方便,但是更灵活,因为它确实是一个库而不是一个固定的语言特性。

复制代码

 1 // C#
 2 lock( mut_x ) {
 3     ... use x ...
 4 }
 5  
 6 // C++11 without lambdas: already nice, and more flexible (e.g., can use timeouts, other options)
 7 {
 8     lock_guard<mutex> hold { mut_x };
 9     ... use x ...
10 }
11  
12 // C++11 with lambdas, and a helper algorithm: C# syntax in C++
13 // Algorithm: template<typename T> void lock( T& t, F f ) { lock_guard hold(t); f(); }
14 lock( mut_x, [&]{
15     ... use x ...
16 });

复制代码

 

熟悉一下lambda吧,你会发现他们很有用,并不只是在c++中,它们已经在几个主流语言中得到支持并且流行开来。

回到顶部

7. Move/&&


把move当作是对拷贝的优化最合适不过了,虽然它也包含其他方面的东西(像完美转发(perfect forwarding))
move语义改变了我们设计API的方式。我们会越来越多的将函数设计成return by value。

复制代码

 1 // C++98: alternatives to avoid copying
 2 vector<int>* make_big_vector(); // option 1: return by pointer: no copy, but don't forget to delete
 3 :::
 4 vector<int>* result = make_big_vector();
 5  
 6 void make_big_vector( vector<int>& out ); // option 2: pass out by reference: no copy, but caller needs a named object
 7 :::
 8 vector<int> result;
 9 make_big_vector( result );
10  
11 // C++11: move
12 vector<int> make_big_vector(); // usually sufficient for 'callee-allocated out' situations
13 :::
14 auto result = make_big_vector(); // guaranteed not to copy the vector

复制代码

 

如果你想获得比copy更高效的办法,对你的类型使用move语义吧。
 

回到顶部

8. 统一的初始化和初始化列表


没有发生变化的:当初始化一个non-POD或者auto的本地变量时,继续使用熟悉的不带额外花括号{}的=语法。

1 // C++98 or C++11
2 int a = 42;        // still fine, as always
3  
4 // C++ 11
5 auto x = begin(v); // no narrowing or non-initialization is possible

 

在其他情况中(特别是随处可见的使用()来构造对象),使用花括号{}会更好。使用花括号{}能避免一些潜在的问题:你不会突然得到一个收缩转换(narrowing conversions)后的值(比如,float转换成int),也不会有偶尔突发的未初始化POD成员变量或者数组的存在,也能避免在c++98中会碰到的奇怪事:你的代码编译没问题,你需要的是变量但实际上你声明了一个函数,这都源于C++声明语法的模糊不清,Scott Meyers的著名说法:“C++最令人苦恼的解析”。通过使用新风格的语法上面解析问题会不复存在。

复制代码

 1 // C++98
 2 rectangle       w( origin(), extents() );   // oops, declares a function, if origin and extents are types
 3 complex<double> c( 2.71828, 3.14159 );
 4 int             a[] = { 1, 2, 3, 4 };
 5 vector<int>     v;
 6 for( int i = 1; i <= 4; ++i ) v.push_back(i);
 7  
 8 // C++11
 9 rectangle       w   { origin(), extents() };
10 complex<double> c   { 2.71828, 3.14159 };
11 int             a[] { 1, 2, 3, 4 };
12 vector<int>     v   { 1, 2, 3, 4 };

复制代码

 

新的{}语法在几乎任何地方都能出色的工作。

1 // C++98
2 X::X( /*...*/ ) : mem1(init1), mem2(init2, init3) { /*...*/ }
3  
4 // C++11
5 X::X( /*...*/ ) : mem1{init1}, mem2{init2, init3} { /*...*/ }

 

最后,有时候传递不带(type-named temporary)的函数参数是很方便的:
void draw_rect( rectangle );
 

1 // C++98
2 draw_rect( rectangle( myobj.origin, selection.extents ) );
3  
4 // C++11
5 draw_rect( { myobj.origin, selection.extents } );

 

我不喜欢使用花括号{}的唯一地方是在初始化一个非POD变量的时候,像 auto x= begin(v);使用花括号会使代码不必要的丑陋,因为我知道了它是一个类类型,所以我不必担心收缩转换,并且现代编译器已经对额外的拷贝(或者额外move,如果类型是move-enabled)进行了优化。

 

 


作者: HarlanC 

博客地址: http://www.cnblogs.com/harlanc/ 
个人博客: http://www.harlancn.me/ 
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 原文链接 
 

标签: C++ 11

好文要顶 关注我 收藏该文  

HarlanC
关注 - 2
粉丝 - 67

+加关注

4

0

« 上一篇:读书笔记 effective c++ Item 27 尽量少使用转型(casting)
» 下一篇:读书笔记 effective c++ Item 28 不要返回指向对象内部数据(internals)的句柄(handles)

posted @ 2017-03-05 10:16 HarlanC 阅读(10384) 评论(0) 编辑 收藏

刷新评论刷新页面返回顶部

注册用户登录后才能发表评论,请 登录 或 注册,访问网站首页。

【推荐】超50万C++/C#源码: 大型实时仿真组态图形源码
【活动】看雪2019安全开发者峰会,共话安全领域焦点
【培训】Java程序员年薪40W,他1年走了别人5年的路

相关博文:
· [C++][编程风格]C++命名规则
· [c++]初识c++钩子
· 学习C++,热爱C++
· C++ Traits
· C++学习笔记(c++入门)

 

文章来源:https://www.cnblogs.com/harlanc/p/6504431.html

【C/C++】C++98基础上的C++11新特性 一、新语法 1.自动类型推导auto auto的自动推导,用于从初始化表达式中推断出变量的数据类型。 //C++98 int a = 10; string s = "abc"; float b = 10.0; vector&lt;int&gt; c; vector&lt;vector&lt;int&gt; &gt; d; map&lt;int, string&gt; m; m[1] = "... 阅读详情

相关推荐

C++98与C++14:时代变迁下的编程语言进化

在编程世界中,C++无疑是一种强大且流行的语言。自其诞生以来,C++已经经历了多个版本的迭代和更新,其中C++98和C++14是两个具有里程碑意义的版本。本文将详细介绍这两个版本之间的区别,帮助读者更好地理解C++语言的进化历程。

笔者从事电信媒体开发多年,愿意将多年的开发经验分享给同行 1989

C++98和C++11的特性和改进

需要注意的是,相较于 C++11、C++14 和 C++17,C++98 的新特性相对较少,C++11 引入的新特性更加丰富和强大。类型推断:C++11 引入了 decltype 关键字和更加灵活的模板类型推导规则,提高了 C++ 中类型推断的能力。新的标准库组件:C++11 引入了新的标准库组件,如正则表达式库、元组库、随机数库等,增强了 C++ 标准库的功能。总的来说,C++11 相较于 C++98 引入了许多重要的新特性和改进,使得 C++ 编程更加方便、灵活和高效,提高了代码的质量和效率。

m0_60352504的博客 1834

【达梦8】多实例监视集群的部署测试

确认监视器具有状态确认和自动接管两个功能。在数据守护系统的故障自动切换模式下,必须部署一个确认监视器,否则在出现数据库故障时,会导致数据库服务中断。DM 提供了两种确认监视器的配置形式,分别为单实例和多实例。但是当单实例确认监视器故障时,无法继续进行集群的故障自动接管和备库故障确认,影响正常使用,故提供了多实例确认监控器来进一步提高集群的高可用性。在多实例确认监视器中,只有一个实例作为确认监视器提供服务,其它实例作为备库存在而不提供服务。

weixin_45335507的博客 1675

C++发展历史C++98和C++11详细介绍

C++发展历史C++98和C++11详细介绍

weixin_38834817的博客 2040

实战指南:UOS专业版命令行高效下载离线安装包及依赖

本文提供了一份UOS专业版离线安装包的实战下载指南。针对无外网环境下的软件部署难题,详细介绍了如何通过命令行精准获取软件包名,并利用`apt download`命令高效下载主程序及其所有依赖。文章重点解析了使用`apt install --dry-run`模拟安装来完整获取依赖包的方法,并给出了离线安装、问题排查及自动化脚本编写等高级技巧,帮助管理员和运维人员实现可靠的批量离线部署。

honey的博客 1110

博途WinCC多语言项目配置指南

在博途(TIA Portal)中为WinCC项目配置多语言功能,需通过系统化步骤实现界面文本的动态切换。

dhaimo的博客 2474

【C++】:C++11新特性

在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称。不过由于C++03(TC1)主要是对C++98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。从C++0x到C++11,C++标准10年磨一剑,第二个真正意义上的标准珊珊来迟。相比于。

优快云官方认证C/C++研发领域优质创作者 优快云官方2023年成都赛道Top3 第16届蓝桥杯C/C++软件赛四川赛区二等奖 带你玩转C/C++ 数据结构与算法 Linux系统编程/Linux网络编程 MySQL数据库 软件测试开发 1066

编译原理考试大题分析【太原理工大学】

看完本篇大题拿 85% 的分应该没问题,TYUT 太原理工大学编译原理期末考试。

m0_52861684的博客 1万+

【c++11】c++11特性

c++11

Tom_猫的博客 428

SAP_SD模块深度解析SAP信用检查中的“未清数量”取值逻辑

确认数量 vs 订单数量:如果系统配置了可用性检查(ATP),并且订单只确认了部分数量,信用检查通常只占用已确认数量的额度(具体取决于信用组的配置)。在SAP中,未清订单数量的计算并非简单读取订单行项目的目标数量(VBAK-KWMENG),而是基于**计划行(Schedule Lines)**层级来汇总的。状态的转换点:当交货单创建(VL01N)并保存时,这部分数量对应订单的“未清订单数量”减少,“未清交货数量”增加。业务人员眼中的未清数量很简单:“我卖了100个,发了30个,未清就是70个”。

我小时候很黑的博客 314

【AutoSAR CAN】04 - 如何使用Davinci Configurator Pro工具配置CAN的波特率

改参数为Tx Arbitration start delay value ,可用于延迟仲裁过程的起始点,用来补偿CAN收发器及线路的传输延迟,以优化传输性能。有关详细信息,请参阅硬件手册。该参数指定采样点模式,即选择多少个采样点的数量,如果选择了每比特三个样本选项,则该点标记第三个样本的位置;我们要配置CAN的波特率,其实就是要弄明白 CAN 控制器的位时序即可,具体的理论部分和EB的配置部门可参考文章《该参数表示传播延迟有多少个时间单位Tq,即上文中的Propagation delay/PROGSEG。.

2602

C++11的历史和统一的初始化列表

c++各标准介绍,c++改进初始化列表,initializer_list类模板

m0_73693552的博客 906

【2026年华为暑期实习(AI)-4月29日-第一题- 选择题】(题目+思路+Java&C++&Python解析+在线测试)

本文摘要涵盖了机器学习和深度学习中的多个核心概念与技术,包括非负矩阵分解、条件数、MobileNet创新点、LDA降维、大模型评测指标、半精度训练、多任务学习、GPU存储层次、正则化、张量并行等。通过12道单选题和8道多选题的形式,系统性地考察了相关理论原理、应用场景及工程实践要点。题目设计注重概念准确性(如LDA目标函数)、技术细节(如Megatron-LM的并行策略)与实际应用(如FP16训练动机),并包含概率统计(二项分布)和数值计算(微分误差分析)等数学基础内容,全面检验读者对AI领域关键知识的掌握

m0_73659489的博客 143

【C++篇】C++11入门:踏入C++新世界的大门

C++98/03:在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称。不过由于C++03(TC1)主要是对C++98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。从C++0x到C++11:C++标准10年磨一剑,第二个真正意义上的标准珊珊来迟。

2509_93923260的博客 620

UE5实现建筑剖切效果

UE5实现建筑剖切效果

专注GIS开发 8464

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

C++11:现代C++的演变与提升

在2003年,C++标准委员会发布了一份技术勘误表(简称TC1),使得C++03取代了C++98成为C++标准的最新版本。然而,C++03(TC1)主要集中于修复C++98中的缺陷,而语言的核心部分并没有重大变化。因此,人们通常将这两个标准统称为C++98/03。C++11,这个被称为“C++0x”的标准,经过十年的发展终于正式发布。与C++98/03相比,C++11带来了许多显著的变化和改进。

htw250056的博客 1212

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

C++奇迹之旅:列表初始化和std::initializer_list(C++11第一篇)

在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称。不过由于C++03(TC1)主要是对C++98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。从C++0x到C++11,C++标准10年磨一剑,第二个真正意义上的标准珊珊来迟。

a_sen的博客 1635

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

C++11

C++11

m0_73751295的博客 321

C++ 11 基础

简单介绍 C++11 的一些基本语法

m0_68102654的博客 935
上一篇: C++:线程(std::thread)
下一篇: C++ 11会带来什么影响?
Poo_Chai
博客等级 码龄9年 178粉丝 117原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值