生活工程体验信仰哲学精神
投稿投诉
精神世界
探索历史
哲学文学
艺术价值
信仰创造
境界审美
体验技术
技能工具
工程信息
医学生产
生活运用
操作能力

玩转C17的十个特性

6月6日 断龙塔投稿
  C迭代速度相对来说还是比较慢的,2010年以后,C的新版本迭代速度有所加快,这一点,从C标准版本的历史发布图1就可以看出来:
  笔者将这些特性大体上分为三类:语法糖、性能提升和类型系统。
  语法糖
  这里所说的语法糖,并不是严格意义上编程语言级别的语法糖,还包括一些能让代码更简洁更具有可读性的函数和库:
  结构化绑定
  c17最便利的语法糖当属结构化绑定。结构化绑定是指将array、tuple或struct的成员绑定到一组变量上的语法,最常用的场景是在遍历mapunorderedmap时不用再声明一个中间变量了:prec17for(constautokv:map){constautokeykv。constautovaluekv。。。。}c17for(constauto〔key,value〕:map){。。。}
  :严格来说,结构化绑定的结果并不是变量,c标准称之为名字别名,这也导致它们不允许被lambda捕获,但是gcc并没有遵循c标准,所以以下代码在gcc可以编译,clang则编译不过for(constauto〔key,value〕:map){〔key,value〕{std::coutkey:valuestd::}();}
  在clang环境下,可以在lambda表达式捕获时显式引入一个引用变量通过编译for(constauto〔key,value〕:map){〔keykey,valuevalue〕{std::coutkey:valuestd::}();}
  另外这条限制在c20中已经被删除,所以在c20标准中gcc和clang都可以捕获结构化绑定的对象了。
  std::tuple的隐式推导
  在c17以前,构造std::pairstd::tuple时必须指定数据类型或使用std::makepairstd::maketuple函数,c17为std::pairstd::tuple新增了推导规则,可以不再显示指定类型。prec17std::pairint,std::stringp1{3。14,pis};autop1std::makepair(3。14,pis);c17std::pairp3{3。14,pis};
  ifconstexpr
  ifconstexpr语句是编译期的if判断语句,在C17以前做编译期的条件判断往往通过复杂SFINAE机制或模版重载实现,甚至嫌麻烦的时候直接放到运行时用if判断,造成性能损耗,ifconstexpr大大缓解了这个问题。比如我想实现一个函数将不同类型的输入转化为字符串,在c17之前需要写三个函数去实现,而c17只需要一个函数。prec17templatetypenameTstd::stringconvert(Tinput){returnstd::tostring(input);}constchar和string进行特殊处理std::stringconvert(constcharinput){}std::stringconvert(std::stringinput){}c17templatetypenameTstd::stringconvert(Tinput){ifconstexpr(std::issamevT,constcharstd::issamevT,std::string){}else{returnstd::tostring(input);}}
  if初始化语句
  c17支持在if的判断语句之前增加一个初始化语句,将仅用于if语句内部的变量声明在if内,有助于提升代码的可读性。且对于lockiterator等涉及并发RAII的类型更容易保证程序的正确性。c17std::mapint,std::std::guardedbymxintdemo(){if(autoitm。find(10);it!m。end()){returnitsecond。size();}if(charbuf〔10〕;std::fgets(buf,10,stdin)){m〔0〕}if(std::lockguardlock(mx);sharedflag){unsafeping();}if(intcountReadBytesWithSignal(s)){publish(count);raise(s);}if(constautokeywords{if,for,while};std::ranges::anyof(keywords,〔tok〕(constcharkw){})){std::cerrT}}
  性能提升
  std::sharedmutex
  sharedmutex是c的原生读写锁实现,有共享和独占两种锁模式,适用于并发高的读场景下,通过reader之前共享锁来提升性能。在c17之前,只能自己通过独占锁和条件变量自己实现读写锁或使用c14加入的性能较差的std::sharedtimedmutex。以下是通过sharedmutex实现的线程安全计数器:c17classThreadSafeCounter{public:ThreadSafeCounter()Multiplethreadsreaderscanreadthecountersvalueatthesametime。unsignedintget()const{std::sharedlocklock(mutex);}Onlyonethreadwritercanincrementwritethecountersvalue。unsignedintincrement(){std::uniquelocklock(mutex);}Onlyonethreadwritercanresetwritethecountersvalue。voidreset(){std::uniquelocklock(mutex);value0;}private:mutablestd::unsignedintvalue0;};
  std::stringview
  std::stringview顾名思义是字符串的视图,类成员变量包含两个部分:字符串指针和字符串长度,std::stringview涵盖了std::string的所有只读接口。std::stringview对字符串不具有所有权,且兼容std::string和constchar两种类型。
  c17之前,我们处理只读字符串往往使用conststd::string,std::string有两点性能优势:兼容两种字符串类型,减少类型转换和内存分配。如果传入的是明文字符串constchar,conststd::string需要进行一次内存分配,将字符串拷贝到堆上,而std::stringview则可以避免。在处理子串时,std::string::substr也需要进行拷贝和分配内存,而std::stringview::substr则不需要,在处理大文件解析时,性能优势非常明显。fromhttps:stackoverflow。coma40129046author:PavelDavydovstringview的removeprefix比conststd::string的快了15倍stringremoveprefix(conststringstr){returnstr。substr(3);}stringviewremoveprefix(stringviewstr){str。removeprefix(3);}staticvoidBMremoveprefixstring(benchmark::Statestate){std::stringexample{asfaghdfgsghasfasg3423rfgasdg};while(state。KeepRunning()){autoresremoveprefix(example);autoresremoveprefix(stringview(example));forstringviewif(res!aghdfgsghasfasg3423rfgasdg){throwstd::runtimeerror(badop);}}}
  std::mapunorderedmaptryemplace
  在向std::mapunorderedmap中插入元素时,我们往往使用emplace,emplace的操作是如果元素key不存在,则插入该元素,否则不插入。但是在元素已存在时,emplace仍会构造一次待插入的元素,在判断不需要插入后,立即将该元素析构,因此进行了一次多余构造和析构操作。c17加入了tryemplace,避免了这个问题。同时tryemplace在参数列表中将key和value分开,因此进行原地构造的语法比emplace更加简洁std::mapstd::string,std::emplace的原地构造需要使用std::piecewiseconstruct,因为是直接插入std::pairkey,valuem。emplace(std::piecewiseconstruct,std::forwardastuple(c),std::forwardastuple(10,c));tryemplace可以直接原地构造,因为参数列表中key和value是分开的m。tryemplace(c,10,c)
  同时,c17还给std::mapunorderedmap加入了insertorassign函数,可以更方便地实现插入或修改语义。
  类型系统
  c17进一步完备了c的类型系统,终于加入了众望所归的类型擦除容器(TypeErasure)和代数数据类型(AlgebraicDataType)
  std::any
  std::any是一个可以存储任何可拷贝类型的容器,C语言中通常使用void实现类似的功能,与void相比,std::any具有两点优势:std::any更安全:在类型T被转换成void时,T的类型信息就已经丢失了,在转换回具体类型时程序无法判断当前的void的类型是否真的是T,容易带来安全隐患。而std::any会存储类型信息,std::anycast是一个安全的类型转换。std::any管理了对象的生命周期,在std::any析构时,会将存储的对象析构,而void则需要手动管理内存。
  std::any应当很少是程序员的第一选择,在已知类型的情况下,std::optional,std::variant和继承都是比它更高效、更合理的选择。只有当对类型完全未知的情况下,才应当使用std::any,比如动态类型文本的解析或者业务逻辑的中间层信息传递。
  std::optional
  std::optional代表一个可能存在的T值,对应Haskell中的Maybe和RustOCaml中的option,实际上是一种SumType。常用于可能失败的函数的返回值中,比如工厂函数。在C17之前,往往使用T作为返回值,如果为nullptr则代表函数失败,否则T指向了真正的返回值。但是这种写法模糊了所有权,函数的调用方无法确定是否应该接管T的内存管理,而且T可能为空的假设,如果忘记检查则会有SegFault的风险。prec17ReturnTypefunc(conststd::stringin){ReturnTyperetnewReturnTif(in。size()0)。。。}c17更安全和直观std::optionalReturnTypefunc(conststringin){ReturnTif(in。size()0)。。。}
  std::variant
  std::variantT,U,。。。代表一个多类型的容器,容器中的值是制定类型的一种,是通用的SumType,对应Rust的enum。是一种类型安全的union,所以也叫做taggedunion。与union相比有两点优势:可以存储复杂类型,而union只能直接存储基础的POD类型,对于如std::vector和std::string就等复杂类型则需要用户手动管理内存。类型安全,variant存储了内部的类型信息,所以可以进行安全的类型转换,c17之前往往通过unionenum来实现相同功能。
  通过使用std::variantT,Err,用户可以实现类似Rust的std::result,即在函数执行成功时返回结果,在失败时返回错误信息,上文的例子则可以改成:std::variantReturnType,Errfunc(conststringin){ReturnTif(in。size()0)returnErr{inputisempty};。。。return{ret};}
  需要注意的是,c17只提供了一个库级别的variant实现,没有对应的模式匹配(PatternMatching)机制,而最接近的std::visit又缺少编译器的优化支持,所以在c17中std::variant并不好用,跟Rust和函数式语言中出神入化的SumType还相去甚远,但是已经有许多围绕std::variant的提案被提交给c委员会探讨,包括模式匹配,std::expected等等。
  总结一下,c17新增的三种类型给c带来了更现代更安全的类型系统,它们对应的使用场景是:std::any适用于之前使用void作为通用类型的场景。std::optional适用于之前使用nullptr代表失败状态的场景。std::variant适用于之前使用union的场景。
  总结
  以上是笔者在生产环境中最常用的c17特性,除了本文描述的十个特性外,c17还添加了如lambda值捕获this,钳夹函数std::clamp(),强制检查返回值〔〔nodiscard〕〕等非常易用的特性,本文篇幅有限不做赘述,欢迎有兴趣的读者自行探索
投诉 评论

裁员可能只是互联网行业风险的开始据美国企业服务数据库公司Crunchbase统计,截至2022年11月中旬,美国科技行业今年已有超过6。7万名员工在大规模裁员中被解雇,不少尚未裁员的公司也纷纷停止招聘或缩减招……玩转C17的十个特性C迭代速度相对来说还是比较慢的,2010年以后,C的新版本迭代速度有所加快,这一点,从C标准版本的历史发布图1就可以看出来:笔者将这些特性大体上分为三类:语法糖、性能提升……三大银行向碧桂园提供超1500亿元授信额度支持公司正常运营需11月24日,碧桂园控股有限公司与中国工商银行股份有限公司、中国银行股份有限公司、中国邮政储蓄银行股份有限公司分别签署战略合作协议,深化银企合作。根据协议,碧桂园共获得三家银行……宝妈关注的孕酮值真的能决定宝宝好不好吗?百佳玛丽亚刘花玉医生接诊孕早期宝妈。红网时刻新闻12月1日讯(通讯员刘阳)在孕初期的时候,有那么一部分宝妈,她们隔三差五就跑医院,每次来都是一句话:医生,你帮我查查孕酮吧……12月1日中午,市场传来三大消息,下午行情怎么走?今天是12月1号星期四,中午12点50分,刚得知3个消息,如下所示:1、消息一:广州多家银行:可延期还房贷延长期限最长可达到12个月个人观点:我觉得在人性化方面,广……格林我穿这件球衣已经11年,我当然有兴趣终老勇士勇士前锋德雷蒙德格林近日接受了专访。谈到自己的勇士生涯,格林说:我已经穿这身球衣11年了,我不知道别的事情。所以,如果你说,‘你不快乐了吗?’我也不知道别的啊。在过去的1……王者荣耀12月1日更新新皮肤新英雄,多位英雄调整王者荣耀12月1日,下午三点开启不停机更新,具体内容如下:一、英雄方面1、新英雄赵怀真上线赵怀真定位为战士,可以打对抗路,当然也可以打野技能介绍:被动:……男士秋冬穿搭方案大将之风360行闪光时刻在商海沉浮,若想有大作为,必须要有大将之风。其最直观的体现方式,就是着装。这一期,助你成为商界精英!前面我们提到过巴尔玛肯外套,今天想要介绍的堑壕外……半夜老醒睡不了整觉!多是这3处堵了,3个方法一觉到天亮大家好,我是李医生。很多人睡到半夜老是醒,并且啊,还挺准点,有的一点多,有的三点多。为什么醒呢,有的是做梦,一下子就惊醒了,有的是睡得轻,有点动静就醒了。如果你是这样,就……我完成作业了我的手机有两天不好用。我觉得应该是系统升级的过程。我的眼睛看不了黑屏,有了黑屏我不能看。这两天系统回复正常了,我能回复朋友了。每天系统提示无数次99。老……穷其一生寻一个同频共振的人房琪的新书大家都看了吗?还记得当初房琪的一句他强任他强,清风拂山岗,十五六岁的那股清风越过重重的山岗吹到今天你也还是最好的年纪。让镜头前的张含韵哭得稀里哗啦的,也让屏幕前……我科学家首次成功制备可用于锂电池的金刚石纳米线金刚石纳米线是一种一维的金刚石基纳米碳材料,具有与碳纳米管相媲美的强度,但其应用一直受限于产物结构的无序性。近日,北京高压科学研究中心研究人员以生物基平台化合物脱水粘酸作为反应……
残疾人生活状况调查与研究记录我的上岸之旅15之旧的不去新的不来LoroPianaCocooning系列被羊绒包裹着的轻松愉坚持下去,全力以赴自律生活Python开发飞机大战小游戏代码开源连续19年蝉联内存第一不是盖的!金士顿疯狂杀价友商都懵圈了承接东部地区产业转移,攀枝花准备好了吗?淘宝信用卡支付怎么开通信用卡支付开通流程解读投屏行业独角兽乐播投屏有何技术优势?微信什么时候才实现双删最新发布河南省又一批建设项目名单公布,看看有你在的城市吗?团队凝聚力读后感二篇女性健康:更年期慎用雌激素药物工厂鼠害防治措施有哪些《诗话周易》第22卦:贲装饰美化终有一天你会发现,原来哪份工作都一样禽流感的症状(禽流感的临床症状)男人不能结婚的是什么病2010。4。11。第7日难忘的读书节二货屌丝的恋爱段子古代最勇武皇帝身兼将军和帝王渔家傲(彭门道中早起)取舍教材内容,让课本服务教学

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找