ACU前采访视频直播

周五,我与凯文·卡彭特坐下来,就我将于4月17日进行的ACCU演讲和其他话题进行了一次简短的(12分钟)采访。

提前为我的声音质量道歉:自从东京国际标准化组织(ISO)会议之后,我就一直受着一些错误的困扰,在这次采访之后,我失声了好几天……我们及时录制了这段视频!

Kevin的问题是关于这些主题的顺序(以及我的简短回答):

  • 聊我的ACCU话题(安全和cppfront更新)
  • 跳上讲台,谈论C++一个小时,真的很容易吗(没有;或者至少对我来说,不太好)
  • 在ISO标准化中,如何在添加功能和记录所做工作之间找到平衡点(感谢Reddit旅行报告的合著者!)
  • ISO C++会议经常有很多来宾,包括定期的高中班(是的,现在是这样了)
  • 安全、C++和cppfront主题
  • 凯文的外衣:“现在就去拿ACCU的票!”

有效的并发课程和即将举行的会谈

随着冬季ISO会议的结束,我们将进入春季会议季!

ACCU 2024年会议。4月17日,我将发表一篇关于C++当前和未来发展的演讲,我计划根据我最近的文章讨论安全性“上下文中的C++安全”和进度更新cppfront前部。我也期待着这三位主讲人的到来:

  • 劳拉·萨维诺,你可能还记得她几个月前在2023年CppCon上做了一次出色的主题演讲。劳拉,再次感谢你的精彩演讲!
  • 比约恩·法勒(Björn Fahler)不仅开发了有用的库,而且很擅长命名它们(特朗佩洛尔,我在看你![sic])。
  • Inbal Levi是ISO C++委员会(负责C++标准库设计的库演化工作组)中两个最大的小组之一,他还参与了许多其他C++会议的组织和运行。

有效并发在线课程。4月22日至25日,我将进行为期四天半的在线在线公共课程,主题是C++中的高性能低延迟编码(参见课程大纲的链接)。CEST每天14.00至18.00的时间旨在对欧洲、中东和非洲地区任何地方的与会者的家乡时区以及美洲的早起者友好。如果你生活在这样一个时代不适合你的地方,并且你想要一个对你的家乡时区更友好的课程,请电子邮件:Alfasoft让他们知道!如果这些时间适合您,并且您对高性能和低延迟编码感兴趣,以及如何在使用C++17、20和23的现代硬件体系结构上实现它们,那么您可以立即注册.

4月以后,今年晚些时候,我将在这些活动中亲自进行演讲:

11月会议的详细信息将很快在他们的网站上公布。

我期待着今年能与你们中的许多人当面或在线聊天!

行程报告:冬季ISO C++标准会议(日本东京)

不久前,ISO C++委员会完成了在日本东京举行的第三次C++26会议。我们的东道主,丰田编织为周一至周六的六天会议安排了高质量的设施。我们曾经220多名与会者,约三分之二的人在现场,其他人通过Zoom远程访问,正式代表21个国家这使得我们有史以来规模最大的会议在数字上大致持平,与2020年布拉格会议(Prague 2020)的出席人数大致相同,该会议在疫情封锁前几周交付了C++20然而,请注意,这并不是一个简单的比较,因为大流行前的会议都是现场会议,而且自从大流行以来,它们一直是混合的。但这表明了C++标准化正在得到大力参与。

在每次会议上,我们都会有从未参加过的新与会者,这次我们欢迎超过30名新的首次与会者,大多数是住院的,人数在上面。(这些数字是针对技术参与者的,不包括我们也有观察员,包括一班当地高中生一天中的一部分时间来参观,类似于11月在科纳举行的上一次会议上,另一班当地高中生的情况。这些天,我们定期邀请高中代表团作为观察员s、 再次欢迎他们!)

委员会目前有23个活跃的小组,其中16个小组在一周内平行开会。一些小组一周都在跑步,另一些小组则根据他们的工作量,跑几天或一天或一晚上的一部分。您可以找到ISO程序的简要摘要在这里.

本周会议:C++26第三次会议

在6月和11月的前两次会议上,委员会通过了C++26的前63个修改建议,其中包括许多在我们完成C++23时已经准备好举行几次会议的修改建议,当时我们正在等待C++26train的开放通过。有关这些亮点,请参见六月旅行报告11月出行报告.

这一次,委员会采用了C++26的下一组特性,并在其他特性上取得了重大进展,这些特性现在有望在C++26中及时完成。

以下是一些亮点……请注意,这些链接指向每篇论文的最新公开版本,其中一些在会议上进行了调整,然后才被批准;链接会跟踪并在上传到公共站点后自动查找更新版本。

C++26采用:核心语言更改/功能

核心语言通过了10篇论文,包括以下…

P2573R2“=删除(”应该有原因“)”通过李一禾对=delete的操作与对static_assert的操作相同:它允许编写字符串作为原因,这使得库开发人员更容易将高质量的编译时错误消息作为编译器自身错误消息输出的一部分提供给用户。谢谢,一和!

下面是本文中的一个示例,该示例现在将合法,并生成与此处所示类似的错误消息:

类不可复制{公众:// ...NonCopyable()=默认值;//复制成员不可复制(const NonCopyable&)=delete(“由于此类管理独特的资源\不支持复制;改用move。");NonCopyable&运算符=(const NonCopyable&)=delete(“由于此类管理独特的资源\不支持复制;改用move。");//改为提供移动成员};<source>:16:17:错误:调用已删除“NonCopyable”的构造函数:由于此类管理唯一资源,因此不支持复制;改用move。不可复制的nc2=nc;^     ~~

P2795R5“未初始化读取的错误行为”通过托马斯·科普是对C++的一个重大更改,它将通过提供减少未定义行为的工具来帮助我们进一步提高安全性,特别是它删除了一些未初始化对象的未定义行为。

我只能引用报纸上的话:

摘要:我们建议通过为C++添加一种新的行为来解决读取默认初始化的自动变量(“未初始化读取”)的安全问题。这种新行为称为错误行为,允许我们正式谈论“buggy”(或“不正确”)代码,也就是说,代码并不意味着它应该意味着什么(在某种意义上,我们将讨论)。这种行为在表示编程错误的意义上是“错误的”,在不构成安全风险的意义上也是定义良好的。

随着社区对安全性的兴趣增加,以及由此类错误导致的漏洞被利用的记录越来越多,有人呼吁修复C++。最近第2723R1页建议通过将未定义的行为更改为定义良好的行为来修复此问题,特别是将初始化定义为零。我们将在下面讨论,这种定义良好的行为的扩展将极大地损害C++代码的可理解性。事实上,如果我们既想保持C++的表达能力,又想解决安全问题,我们需要一种新的行为。

读取未初始化的值绝对不是有意的,这是代码编写不正确且需要修复的明确标志。同时,我们确实给这个代码定义了明确的行为,如果这种情况还没有被诊断出来,我们希望程序是稳定和可预测的。这就是我们所说的错误行为.

换句话说,读取未初始化的值仍然是“错误的”,但如果您确实读取了它,并且实现没有以其他方式阻止您,那么您将获得一些特定的值。一般来说,实现必须表现出定义的行为,至少在发出诊断之前(如果有的话)。执行错误行为时,不存在与未定义行为相关的后果风险(例如,执行源代码中未反映的指令、时间旅行优化)。

添加“错误行为”的概念是对C++规范的一个重大更改,这不仅有助于未初始化的读取,而且还可以应用于减少未来其他未定义的行为。谢谢,托马斯!

C++26采用:标准库更改/功能

标准图书馆通过了18篇论文,包括以下…

在“Moar Ranges!”部门,P1068R11“用于生成随机数的矢量API”通过伊利亚·布里洛夫(Ilya Burylov)、帕维尔·迪亚科夫(Pavel Dyakov)、鲁斯兰·阿鲁廷扬(Ruslan Arutyunyan)、安德烈·尼古拉耶夫(Andrey Nikolaev)、和艾琳娜·埃利扎洛娃解决了这样的情况:当你想要一个随机数时,你可能想要更多的随机数,而随机数生成器通常已经成批高效地生成了它们。多亏了他们的论文,这一点现在可以实现了:

标准::数组<std::uint_fast32_t,arrayLength>intArray;标准::mt19937克(777);std::ranges::generate_random(intArray,g);//上述行等于:for(auto-e:intArray)e=g();

在“如果你还没有得到足够的‘Moar Ranges!’”部门,P2542“视图::concat”通过谢慧(音)S.Levent Yilmaz公司提供了一种简单的方法,通过视图工厂高效地连接任意数量的范围。谢谢,惠和利文!以下是本文中的一个示例:

标准::vector<int>v1{1,2,3},v2{4,5},v3{};标准::数组{6,7,8};auto s=标准::视图::单个(9);标准::打印(“{}\n”,标准::视图::concat(v1,v2,v3,a,s));//输出:[1,2,3,4,5,6,7,8,9]

说到串联,你有没有想过自己可以写“my_string_view+my_string”,却惊讶地发现它不起作用?我当然有。不再:P2591R4“串和串视图的级联”通过朱塞佩·达安吉洛为这些类型添加运算符+重载。感谢Giuseppe终于为我们提供了此功能!

P2845“格式化std::filesystem::path”通过维克托·兹维罗维奇(又名格式之王)为文件系统路径提供了一个高质量的std::Format格式化程序,解决了有关引用和本地化的问题。

一组论文由阿利斯代尔·梅雷迪斯从标准库中删除了一些(大多数已经弃用)功能。谢谢你的清理,Alisdair!

P3142R0“使用println打印空白行” 通过阿兰·塔尔博特虽然很小,但提高了生活质量:我们现在可以只编写println()作为println(“”)的等价物。但还不止这些:请参阅论文中的美味附言。(看,艾伦,我们看了整篇报纸。谢谢!)

这些是一些“更大”或“可能引起广泛关注”的论文,只是其中的几个亮点……本周共有28篇论文被采纳,其中包括关于C++26语言和标准库的扩展和修复的其他伟大工作。

针对C++26时间表:合同

合同建议书P2900“C++合同”通过约书亚·伯尔尼、蒂穆尔·多姆勒、安德烈·克尔泽米恩斯基、加什佩·阿泽曼、汤姆·霍尔曼、丽莎·利宾科特、延斯·莫勒、杰森·梅里尔和维勒·沃乌蒂莱宁脱离合同研究小组SG21,首次出现在语言(EWG)和库(LEWG)进化工作组中。LEWG的会议于第一天即周一下午开始,EWG周三花了一整天时间签订合同,安全研究小组SG23的许多成员出席了会议。关于是否应该允许合同有未定义的行为或受其影响,有着热烈的讨论;标准库中是否应使用合同;合同是否应首先作为技术规范(TS,特性分支)在与C++26相同的时间段内发布,以获得更多使用现有库的经验;以及其他方面……所有这些问题将在未来几个月内再次讨论,这只是最初的LEWG和EWG全组设计审查,产生了待观察的反馈。小组在星期四和星期五的另外两次会议中考虑了EWG和LEWG小组的反馈,包括SG21和SG23联合会议。

从现在到6月的下一次混合会议期间,SG21和SG23都将进行电话会议,以进一步改进合同提案。

瞄准C++26:反射

反思建议P2996R2“C++26的反射”通过怀亚特·奇尔德斯、彼得·迪莫夫、巴里·瑞文、安德鲁·萨顿、费萨尔·瓦利,达维德·范德沃德在反思/编译时编程研究小组SG7的基础上取得进展,并于周二首次被主要进化小组EWG和LEWG看到,这是从周二的EWG+LEWG联合会议开始的,而EWG在周二的大部分时间里都花在了针对C++26的初始大组评审上。然后,SG7继续讨论反射和其他主题,包括Andrei Alexandrescu的演讲,内容是确保反射添加了一些小东西,以充分支持灵活的生成性编程。

其他进展

所有分组继续取得进展。其他旅行无疑会涵盖很多事情,但我要指出两件事。

很多人都在关注的一个提议是P2300“标准::执行”(又名“执行人”)MichałDominiak、Georgy Evtushenko、Lewis Baker、Lucian Radu Teodorescu、Lee Howes、Kirk Shoop、Michael Garland、Eric Niebler、和布莱斯·阿德尔斯坦·勒巴赫,它已经通过了C++26的设计批准。这是一篇巨大的论文(45000字,其中20000字是标准规范!这简直是一本书……我的第一本例外C++这本书有62000字),所以图书馆用词小组(LWG)对规范用词进行详细审查需要时间,在这次会议上,LWG花了四分之一的时间完成了对整个论文的第一次审查!他们将继续在电话会议上进行第二次通过,现在对在6月的下一次会议上完成P2300措辞审查持温和乐观的态度。

还有一个有趣的亮点:我们可能都怀疑模式匹配是对未来C++的一个“奠基”提议,但在东京的模式匹配会议期间,发生了一场文字地震,短暂中断了会议!

感谢所有在所有小组工作了一周的专家,他们在本周取得了如此大的成就!

接下来是什么

我们的下一次会议将在6月,美国密苏里州圣路易斯主办比尔·西摩.

总结

再次感谢参加本周会议现场和在线的210多名专家,以及更多通过国家机构参与标准化的专家!

但我们并没有放慢脚步……我们将继续举行小组Zoom会议,然后在三个月后,我们将再次亲自参加会议,并继续向C++26添加功能。再次感谢所有阅读本文的人对C++及其标准化的关注和支持。

上下文中的C++安全

范围。为了更好地讨论C++当前的安全问题和解决方案,我需要包括所有软件所面临的广泛安全威胁的背景。我是ISO C++标准委员会的主席,我在微软工作,但这些是我个人的意见,我希望他们能在编程语言和安全社区之间邀请更多对话。

致谢。非常感谢来自C、C++、C#、Python、Rust、MITRE以及其他语言和安全社区的人们,他们对本材料草稿的反馈非常宝贵,其中包括:Jean-François Bastien、Joe Bialek、Andrew Lilley Brinker、Jonathan Caves、Gabriel Dos Reis、Daniel Frampton、Tanveer Gani、丹尼尔·格里芬、Russell Hadley、Mark Hall、,Tom Honermann、Michael Howard、Marian Luparu、Ulzii Luvsanbat、Rico Mariani、Chris McKinsey、Bogdan Mihalcea、Roger Orr、Robert Seacord、Bjarne Stroustrup、Mads Torgersen、Guido van Rossum、Roy Williams、Michael Wong。

术语(请参见ISO/IEC 23643:2020标准).软件安全“(或“网络安全”或类似内容)意味着使软件能够保护其资产免受恶意攻击者的攻击。软件安全“(或”生命安全“或类似的)意味着使软件免受对人类、财产或环境造成意外伤害的不可接受的风险。编程语言安全“指一种语言(包括其标准库)的静态和动态保证,包括但不限于类型和内存安全,这有助于我们使软件更加安全。当我说“安全”这里的不合格,我指的是编程语言安全,这对软件安全和软件安全都有好处。

我们必须使我们的软件基础设施更加安全,以防网络攻击(如电网、医院和银行)的增加,并随着软件在生命关键系统(如自动驾驶汽车和自动武器)中的使用增加,使其更安全,以防意外故障。

尤其是过去两年,人们更加关注编程语言的安全性,将其作为帮助构建更加安全可靠的软件的一种方式;关于内存安全语言(MSL)的真正好处;C和C++语言安全需要改进-我同意。

但也有一些误解,包括过于狭隘地将编程语言安全作为我们行业的主要安全问题——事实并非如此。最近许多最具破坏性的安全漏洞都发生在MSL中编写的代码上(例如。,日志4j)或者与编程语言无关(例如。,存储在公共GitHub回购上的Kubernetes机密).

在这种情况下,我将重点介绍C++并尝试:

  • 强调需要注意什么(C++的问题是什么),以及我们如何通过构建已经在进行中的解决方案来实现这一目标;
  • 解决一些常见的误解(C++的问题“不是”什么),包括对MSL的实际考虑;
  • 为使用所有语言的程序员留下行动号召。

tl;博士:我不希望C++限制我可以高效表达的内容。我只想C++默认情况下让我执行我们众所周知的安全规则和最佳实践,并让我明确选择退出。然后我仍然可以使用完全现代的C++……只是更好。

让我们深入挖掘。

直接的问题“是”在C++中编写安全漏洞“太容易了”,这些漏洞会被更严格的已知规则所捕获类型、边界、初始化,一生语言安全

在C++中,我们需要从改进这四个类别开始。这些是NIST/NSA/CISA/等推荐使用的所有MSL提供的四个主要改进来源,而不是C++(例子)因此,根据定义,解决这四个问题将使用C++解决NIST/NSA/CISA/等直接问题。(在下面的“问题不是……(1)”中对此进行了详细介绍。)

近年来,包括2023年在内(见图1中突出显示的四行和图2),这四行占经常引用的70%CVE公司与语言记忆不安全相关的(常见[安全]漏洞和暴露)。(然而,“70%的语言记忆不安全CVE”具有误导性;例如,在图1中MITRE 2023年“最危险的弱点”不涉及语言安全,因此超出了分母范围。在下面的“问题不是……(3)”中对此进行了详细介绍。)

C++指南文献已经广泛同意这些类别中的安全规则。确实存在一些相互冲突的指导文献,特别是在禁止异常或运行时类型支持的环境中,因此使用一些替代规则。但对于核心安全规则,例如禁止不安全的强制转换、未初始化的变量和边界外访问,人们达成了共识(见附录)。

C++应该提供一种默认情况下强制执行它们的方法,并在需要时要求显式opt-out。我们可以并且确实可以用C++编写“好”的代码和安全的应用程序。但是,即使是经验丰富的C++开发人员也很容易意外地编写出C++默默接受的“坏”代码和安全漏洞,这将被其他语言视为违反安全规定而拒绝。我们需要标准语言通过实施已知的最佳实践来提供更多帮助,而不是依赖其他非标准工具来推荐它们。

这并不是我们应该解决的语言安全的四个方面。它们只是直接的,是一组明显的低挂果实,既有明确的需求,也有明确的改进方法(见附录)。

注:当然,安全类别是相互关联的。例如,完全类型安全(即访问的对象是其类型的有效对象)要求消除对未分配对象的边界外访问。但是,相反,完全边界安全(即访问的内存在分配的边界内)同样需要消除对更大的派生类型对象的类型安全向下转换,这些派生类型对象似乎会扩展到实际分配之外。

软件安全也很重要。网络攻击迫在眉睫,所以最近的讨论自然更多地集中在安全和CVE上。但是,当我们指定和发展默认的语言安全规则时,我们还必须包括那些深切关注功能安全问题的利益相关者,这些问题没有反映在主要的CVE桶中,但在代码中留下时对生命和财产同样有害。编程语言安全有助于软件安全和软件安全,我们应该从某个地方开始,所以让我们从已知的安全CVE痛点开始(但不是结束)。

在这四个桶中,提高10-50倍(减少90-98%)就足够了

如果C++类型/边界/初始化/生存期漏洞减少90-98%,我们就不会讨论这个问题。所有语言都有CVE,C++只是有更多(C语言更多)。[更新:删除了2024 Rust与C/C++CVE的计数,因为MITRE.org搜索无法准确计算后者。]所以零不是目标;为了实现与MSL提供的语言安全级别同等的安全性,有必要减少90%,减少98%就足够了……而且我认为这有很大的好处完美的反向链接兼容性(即,不改变C++的对象模型及其生命周期模型,它不依赖于通用跟踪垃圾收集,也不限于基于树的数据结构),这对于我们能够像采用其他新版本的C++一样容易地采用现有C++项目中的改进是至关重要的之后,我们可以对其他桶进行额外的改进,例如线程安全和溢出安全。

在这四个桶中实现100%或零CVE是一个错误:

  • 100%是不必要的,因为我们被告知使用的MSL也不存在。在下面的“问题不是……(2)”中有更多关于这方面的内容。
  • 100%是不够的,因为许多网络攻击利用了内存安全之外的安全弱点。

最后2%的成本太高了因为它需要放弃与当今C++代码的链接兼容性和无缝互操作性(或“互操作”)。例如,Rust的对象模型和借用检查器提供了很好的保证,但需要与C++基本不兼容,因此使互操作难以超越通常的C互操作级别。一个原因是Rust的安全语言指针仅限于表示没有循环的树型数据结构;独特的所有权对于实现强大的语言强制别名保证至关重要,但它还要求程序员对任何比树更复杂的东西使用“其他东西”(例如,使用Rc或使用整数索引作为替代指针);这不仅仅是关于链接列表但这是一个简单而著名的示例。

如果我们能够得到98%的改进,并且仍然与现有C++具有完全兼容的互操作,那将是一个值得认真投资的圣杯。

在新的/更新的C++代码中可以实现这四个类别中98%的减少,在现有代码中也可以实现部分减少

至少从2014年起,Bjarne Stroustrup就主张通过“超集的子集”来解决C++中的安全性问题:即首先“超集”添加C++中不可用的基本项,然后“子集”排除现在都有替换项的不安全结构。

从C++20开始,我相信我们已经实现了“超集”,特别是通过标准化跨度,字符串视图(_V)、概念和边界软件范围。我们可能还需要一些其他功能,例如以null结尾的zstring_view,但主要的附加功能已经存在。

现在我们应该“子集”:使C++程序员能够围绕类型和内存安全实施最佳实践,默认情况下,在新代码和代码中,他们可以更新以符合子集。默认情况下启用安全规则不会限制该语言的功能,但需要对非标准实践进行明确的选择,从而减少意外风险。它可能会随着时间的推移而进化,这一点很重要,因为C++是一种活的语言,对手会不断改变他们的攻击。

ISO C++的发展已经在进行C的安全配置文件++附录中的建议是对其的改进,以证明具体的实施,并尝试最大限度地提高其可采用性和有用的影响。例如,每个人都同意许多安全漏洞需要修改代码才能修复。然而,有多少安全漏洞可以在不手动更改源代码的情况下修复,因此只需重新编译启用了安全配置文件的现有代码就能带来一些安全好处?例如,当.size()存在且a是连续容器时,我们可以在每个下标表达式a[b]上默认插入一个调用边界检查0<=b<.size;该检查将对每个相邻的C++标准容器、span、string_view和第三方自定义容器进行开箱即用,不需要库更新(因此也不需要担心ABI中断)。

类似附录中总结的规则可以防止(在编译时、测试时或运行时)我在类型、边界和初始化类别中查看的大多数过去的CVE,并且可以防止许多生命周期的CVE。我估计,通过定义良好且标准化的方式,C++可以在默认情况下启用安全规则,同时保持完美的向后链接兼容性,从而使这些类别的数据量减少大约98%。有关更详细的说明,请参阅附录。

我们可以也应该强调C++代码的可接受性和好处,因为C++代码不容易更改。为遵守安全规则而进行的任何代码更改都会带来成本;更糟糕的是,并不是所有的代码都可以很容易地进行更新以符合安全规则(例如,它很旧而且不被理解,它属于不允许更新的第三方,它属于共享项目,不接受上游更改,也不容易分叉)。这就是为什么上面(以及附录中)我强调C++应该认真尝试在不需要手动更改源代码的情况下尽可能多地提供安全改进,特别是,在清楚的情况下,自动让现有代码做正确的事情(例如,上面提到的边界检查,或者在不需要更改代码的情况下将static_cast指针向下转换为有效的dynamic_cast),通过提供程序员可以选择应用的自动修复(例如,将staticcast指针向下转换的源代码更改为dynamiccast)。尽管在许多情况下,程序员需要深思熟虑地更新代码,以替换无法自动修复的固有不安全结构,但我相信,在一定比例的情况下,我们可以通过以安全规则默认模式重新编译现有代码来提供安全改进,我们应该尝试,因为这对于最大限度地提高安全配置文件的可采用性和影响至关重要。

问题“不是”:一些常见的误解

(1) 问题“不是”定义我们所说的“C++最紧迫的语言安全问题”。我们知道最迫切需要改进的四种安全:类型、边界、初始化和终身安全。

我们知道这四个是低垂的果实(参见上面的“问题”是“……”)。的确,这些仅仅是二十四种“安全”类别中的四种,其中包括安全整数运算。但是:

  • 其他大多数问题要么是小得多的问题来源,要么主要是因为它们促成了这四个主要类别。例如,我们最关心的整数溢出是索引和大小,它们在安全范围内。
  • 大多数MSL也没有解决默认情况下使这些安全的问题,通常是由于检查成本。但所有语言(包括C++)通常都有解决这些问题的库和工具。例如,Microsoft发布了SafeInt库用于C++处理整数溢出,这是opt-in。C#有一个检查算术语言功能处理整数溢出,这是opt-in。默认情况下,Python的内置整数是溢出安全的,因为它们会自动扩展;然而,流行的NumPy固定大小整数类型在默认情况下不检查溢出,并且需要使用选中的函数,这是opt-in。

线程安全显然也很重要,我没有忽视它。我只是指出它不是顶级目标存储桶之一:NIST/NSA/CISA/等推荐的大多数MSL都优于C++(唯一的Rust除外,Python的影响较小)用户 数据有关C++的损坏。MSL的主要改进是程序数据竞争不会破坏语言本身虚拟机(而在C++中,数据竞赛目前是完全没有定义的行为)。一些语言确实提供了一些额外的保护,例如Python保证两个竞争线程不会看到整数的撕裂写入,并减少了由于全局解释器锁(GIL)而导致的其他可能的交错。

(2) 问题“不在于”C++代码没有被正式证明是安全的。

是的,默认情况下,C++代码使编写无声的安全代码变得太容易了(请参阅上面的“问题是”…“)。

但我看到一些人声称,我们需要要求语言在形式上可以证明是安全的,这将是一座过犹不及的桥梁。让CS理论家们非常懊恼的是,主流商业编程语言在形式上并不安全。考虑一些示例:

  • 如前一节所述,我们视为MSL的广泛使用的语言(唯一的Rust除外)都没有声称在结构上是线程安全和无种族的。然而,我们仍然将C#、Go、Java、Python和类似语言称为“安全的”。因此,正式保证线程安全属性并不是被视为足够安全的语言的必要条件。
  • 这是因为语言对安全保证的选择是一种权衡:例如,在Rust中,安全代码仅使用基于树的动态数据结构。与其他安全语言相比,此功能使Rust提供了更强的线程安全保证,因为它可以更容易地推理和控制别名。然而,同样的特性也要求Rust程序更频繁地使用不安全代码来表示通用数据结构,这些数据结构不需要在其他MSL(如C#或Java)中表示不安全代码,等等30%至50%的锈蚀板条箱使用不安全代码,例如与25%的Java库.
  • C#、Java和其他MSL仍然存在使用前初始化和使用后销毁类型的安全问题:它们保证不访问记忆超出其分配的生存期,但对象lifetime是内存生命周期的子集(对象是在原始内存分配和释放之后构造的,在之前销毁/释放;在构造之前和释放之后,内存被分配,但包含可能不代表其类型的有效对象的“原始位”)。如果你有疑问,请跑(不要走)并询问ChatGPT关于Java和C#问题:访问-非构造对象错误(例如,在这些语言中,构造函数中的任何虚拟调用都是“深层”的,并且在派生对象的状态初始化之前在派生对象中执行);使用后处理错误;“复活”虫子;以及为什么这些语言告诉人们永远不要使用终结器。然而,这些都是很棒的语言,我们理所当然地认为它们是安全的语言。因此,正式保证no-use-before-initialized和no-us-eafter-dispose不能被视为足够安全的语言。
  • Rust、Go和其他语言支持消毒器也包括ThreadSanitizer和未定义的行为消毒剂以及fuzzer等相关工具。众所周知,消毒剂仍然是语言安全的补充,而不仅仅是当程序员使用“不安全”代码时;此外,它们不仅仅是发现内存安全问题。据我所知,大规模使用铁锈也会强制使用消毒剂。因此,使用消毒剂不能表明语言是不安全的,我们应该对用任何语言编写的代码使用支持的消毒剂。

注:“使用消毒剂”并不意味着一直使用所有消毒剂。有些消毒剂相互冲突,所以一次只能使用一种。有些消毒剂很昂贵,所以只能定期运行。一些消毒剂不应在生产中运行,包括因为它们的存在可能会产生新的安全漏洞。

(3) 问题“不是”将世界上的C和C++代码迁移到内存安全语言(MSL)可以消除70%的安全漏洞。

MSL太棒了!它们不是银弹。

经常引用的数字是70%吗编程语言引起的C和C++代码中的CVE(报告的安全漏洞)是由于语言安全问题造成的。这个数字是真实的、可重复的,但在新闻界却被严重曲解:我认识的安全专家都不相信,如果我们能挥舞魔杖,立即将世界上所有的代码转换为MSL,那么我们的CVE、数据泄露和勒索软件攻击就会减少70%。(例如,请参见2024年2月的示例分析文件.)

考虑一些原因。

  • 这70%是子集可以通过编程语言安全性来解决的安全CVE。再次参见图1:2023年前10个“最危险的软件缺陷”中的大多数与内存安全无关。2023年许多最大的数据泄露、其他网络攻击和网络犯罪与编程语言无关。2023年,攻击者减少了恶意软件的使用,因为软件变得更加坚固,端点保护有效(CRN)袭击者会追捕群中速度最慢的动物。中列出的大多数问题NISTIR-8397公司平等地影响所有语言,因为它们超越了内存安全(例如。,日志4j)甚至编程语言(例如,自动测试、硬编码机密、启用操作系统保护、字符串/SQL注入、软件材料清单)。有关更多详细信息,请参阅微软对NISTIR-8397的回应,我是其中的编辑。(更多信息请参阅《行动呼吁》。)
  • MSL也会出现CVE,尽管肯定会更少(同样,例如。,日志4j)。例如,请参见锈蚀CVE的MITRE列表其中包括2024年迄今为止的6个。所有程序都使用不安全的代码;例如,请参见结论第节,共节Firouzi等人。研究了C#在StackOverflow上的不安全使用和漏洞的普遍存在,以及所有程序最终调用受信任的本地库或操作系统代码。
  • 大声说出沉默的部分:众所周知,简历是一个不精确的指标。我们使用它是因为它是我们的度量标准,至少对于安全漏洞来说是这样,但我们应该小心使用它。这可能会让你感到惊讶,就像我一样,因为我们听说了很多关于简历的事情。但每当我建议改进C++并通过减少CVE来衡量“成功”时(包括本文中),安全专家坚持认为,CVE不是一个很好的衡量标准……包括之前向我引用70%CVE数字的那些专家;但是,即使没有合理的漏洞利用,也可能会有压力将漏洞报告为漏洞,因为在CVE上获得姓名的好处。2023年8月Python软件基金会成为CVE编号机构(CNA)对于Python和pip发行版,现在可以更好地控制Python和pip CVE。C++社区还没有这样做。
  • CVE只针对软件安全漏洞(网络攻击和入侵),我们还需要考虑软件安全(生命关键系统和对人类的意外伤害)。

(4) 问题“不是”C++程序员不够努力/使用现有工具不够好。挑战是如何更容易地启用它们。

今天,我们为C++代码提供的缓解措施和工具是一个不均衡的组合,默认情况下都是关闭的:

  • 善良。它们是静态工具、动态工具、编译器开关、库和语言功能的混合体。
  • 收购。它们是以多种方式获得的:C++编译器中的内置、可选下载、第三方产品,以及一些需要通过谷歌搜索才能发现的产品。
  • 准确性。现有规则集混合了低误报和高误报的规则。后者实际上是程序员无法接受的,而且它们的存在使得“仅仅采用这整套规则”变得困难
  • 决定论。一些规则,例如依赖于完整调用树的过程间分析的规则,本质上是不确定的(因为当完全评估案例超过可用的空间和时间时,实现会放弃;也称为“尽力”分析)。这意味着相同规则的两个实现可以为相同代码提供不同的答案(因此非确定性规则也不可移植,请参见下文)。
  • 效率。现有规则集混合了诊断成本低和高(有时不可能)的规则。效率不够高而无法在编译器中实现的规则将始终降级为可选的独立工具。
  • 便携性。并非所有供应商都支持所有规则。“符合ISO/IEC 14882(标准C++)”是每个C++工具供应商唯一支持的可移植性。

为了解决所有这些问题,我认为我们需要C++标准来指定一种一致同意的低或零错误正确定性规则的模式,这些规则的成本足够低,可以在构建时在机箱中实现。

行动呼吁

一般来说,作为一个行业,我们必须在编程语言内存安全方面做出重大改进——我们会这样做的。

具体来说,在C++中,我们应该首先瞄准四个关键安全类别,这四个类别是我们的常年经验攻击点(类型、边界、初始化和寿命安全),并将这四个领域中的漏洞降低到新的/更新的C++代码的噪音中,我们可以做到这一点。

但我们也必须认识到,编程语言安全并不是实现网络安全和软件安全的灵丹妙药。这是一场长期战争中的一场战役(甚至不是最大的战役):每当我们硬化我们系统的一部分并使其攻击成本更高时,攻击者总是会转而攻击群中速度最慢的动物。2023年发生的许多最严重的数据泄露事件都与恶意软件无关,但都是由存储不充分的凭据(例如。,Kubernetes的秘密公共GitHub回购)、配置错误的服务器(例如。,暗光束,儿童安全)缺乏测试、供应链漏洞、社会工程以及其他独立于编程语言的问题。苹果的白皮书大约2023年网络犯罪的增长强调改进处理,而不是程序代码的处理,而是数据的处理:“组织必须考虑限制以可读格式存储的个人数据的数量,同时更加努力保护他们确实存储的敏感消费者数据,[包括使用]端到端[E2E]加密。”

无论我们使用什么编程语言,安全卫生都至关重要:

  • 使用您的语言的静态分析器和净化程序。永远不要假装使用静态分析器和消毒剂是不必要的,“因为我使用的是一种安全的语言。”如果您使用的是C++、Go或Rust,那么请使用这些语言支持的分析器和消毒器。如果你是一名经理,不要让你的产品在没有使用这些工具的情况下发货。(再次声明:这并不意味着一直运行所有消毒剂;有些消毒剂会发生冲突,因此不能同时使用,有些很昂贵,因此应该定期使用,有些只应在测试中运行,而不应在生产中运行,包括因为它们的存在可能会产生新的安全漏洞。)
  • 保持所有工具的更新。定期修补不仅适用于iOS和Windows,也适用于编译器、库和IDE。
  • 保护您的软件供应链。对库依赖项使用包管理。跟踪项目的软件物料清单。
  • 不要这样在代码中存储机密。(或者,看在上帝的份上,在GitHub上!)
  • 正确配置服务器,尤其是面向公共互联网的服务器。(启用身份验证!更改默认密码!)
  • 保持非公开数据加密,无论是在静止状态(磁盘上)还是在移动状态(理想情况下是E2E……并反对提议的立法,该立法试图用“只有好人才会使用的后门”来中性化E2E加密,因为不存在这样的事件)。
  • 保持长期投资以保持您的威胁建模最新,以便您可以在对手不断尝试不同攻击方法时保持自适应。

我们需要提高整个行业的软件安全性和软件安全性,特别是通过提高C和C++中的编程语言安全性,而在C++中,在中期内可以实现四个最常见问题领域98%的改进。但是,如果我们只关注编程语言的安全性,我们可能会发现自己正在经历昨天的战争,而忽略了影响以任何语言编写的软件的更大的过去和未来安全隐患。

可悲的是,坏演员太多了。在可预见的未来,我们的软件和数据将继续受到攻击,以任何语言编写并存储在任何地方。但我们可以保护我们的程序和系统,我们也会这样做。

一切安好,愿我们都能继续努力,让2024年更加安全。

附录:说明为什么降低98%是可行的

本附录旨在支持为什么我认为C++代码中类型/边界/初始化/生存期CVE减少98%是可信的。这不是一个正式的建议,而是对在新的和可更新的代码中实现这种改进的具体方法的概述,以及在现有代码中实现改进的方法,我们不能更新,但可以重新编译。这些注释与ISO C++安全小组目前正在进行的建议相一致,如果它们在正在进行的讨论和实验中实现了我的预期,那么我打算在未来的论文中进一步详细介绍它们。

所有四个bucket中的一些建议都有运行时和代码大小开销,特别是检查边界和强制转换。但是,没有理由认为C++中的这些开销必然比其他语言更糟糕,而且我们可以默认启用它们,并且仍然提供了一种选择退出的方法,以便在需要时重新获得完全性能。

注:例如,当使用优化器不提升边界检查的编译器时,边界检查可能会对一些热循环造成重大影响;循环不仅会引发冗余检查,而且可能不会得到其他优化,例如不被矢量化。这就是为什么默认情况下启用边界检查是好的,但所有面向性能的语言还需要提供一种方式来表示“信任我”,并在需要时明确选择越界检查。

本附录是指C++核心指南安全配置文件这是一套关于类型和内存安全的大约24条可执行规则,我是其中的一员。我仅将其作为示例,以展示“什么”是我们可以实施的已知规则,并支持我声称的改进是可能的。它们与其他来源的规则大体一致,例如:C++编程语言关于类型安全的建议;C++编码标准“关于类型安全的章节;这个联合攻击战斗机编码标准;高完整性C++; 这个关于安全配置文件的C++核心指南部分(一小套可执行的安全规则);最近发布的MISRA C++:2023.

“如何”让程序员控制启用这些规则的最佳方式(例如,通过源代码注释、编译器开关和/或其他方式)是一个正交的用户体验问题,目前C++标准委员会和社区正在积极讨论这个问题。

类型安全

强制执行赞成的意见。类型安全配置文件默认情况下。这包括禁止或检查所有不安全的类型转换和转换(例如,static_cast指针向下转换、reinterpret_cast),包括通过C union和vararg进行隐式不安全类型双关。

然而,这些规定尚未在行业中得到系统的执行。例如,近年来,我痛苦地观察到一组重要的类型安全导致的安全漏洞,其根本原因是代码使用static_cast而不是dynamic_cast进行指针向下转换,以及“C++”即使实际问题是没有遵循广为人知的指南来使用该语言现有的安全推荐功能,也会受到指责。现在是使用标准化C++模式的时候了,默认情况下会强制执行这些规则。

注:在某些平台上,对于某些应用程序,dynamic_cast(动态_广播)有妨碍其使用的问题空间和时间开销。许多实现捆绑包dynamic_cast(动态_广播)与所有C++运行时类型化(RTTI)特征(例如。,类型ID),因此需要存储全部潜在的重量级RTTI数据,即使dynamic_cast(动态_广播)只需要一小部分。一些实现还使用了不必要的低效算法dynamic_cast(动态_广播)自身。因此,标准必须鼓励(并且,如果可能的话,强制执行一致性,例如通过设置算法复杂性要求)dynamic_cast(动态_广播)实现更加高效,并且与其他RTTI开销解耦,这样程序员就没有合理的性能理由不使用安全特性。这种脱钩可能需要ABI中断;如果这是不可接受的,标准必须提供替代的轻量级设施,例如快速动态广播它与(其他)RTTI分开,以最小的空间和时间成本执行动态转换。

约束安全性

强制执行赞成的意见。绑定安全配置文件默认情况下,以及保证边界检查。我们还应保证:

  • 禁止使用指针算法(改用std::span);这强制要求指针指向单个对象。如果允许,数组到指针的衰减将仅指向数组中的第一个对象。
  • 只允许使用有界选择的迭代器算法(也可以使用首选范围)。
  • 通过让编译器对形式为a[b]的每个表达式注入自动下标边界检查,所有下标操作都在调用位置进行边界检查,其中a是带有size/ssize函数的连续序列,b是整数索引。当发生冲突时,可以使用全局边界冲突处理程序自定义所采取的操作;一些程序将要终止(默认),其他程序将要记录并继续,抛出异常,与特定于项目的关键故障基础设施集成。

重要的是,后者显式地避免了对每个单独的容器/范围/视图类型进行侵入性的边界检查。在调用站点以非侵入方式自动实现边界检查,可以对每个现有的标准和用户编写的容器/范围/视图类型进行全面的边界检查:向量、span、deque、,或第三方和公司内部库中类似的现有类型将在检查模式下可用,而不需要任何库升级。

在库继续在每个库中添加更多的下标边界检查之前,现在添加自动调用方检查很重要,这样可以避免在调用站点和被调用方重复检查。作为一个反例,C#花了很多年时间来消除重复的调用方和调用方检查,但成功了。NET Core现在更好地解决了这个问题;通过更快地提供自动呼叫端检查,我们可以避免大多数重复的检查消除优化工作。

像range-for循环这样的语言构造在构造上已经是安全的,不需要检查。

在边界检查对性能产生影响的情况下,代码仍然可以在这些路径中显式选择不进行边界检查,以保持完全性能,并且在应用程序的其余部分中仍然进行完全边界检查。

初始化安全

默认情况下,强制进行初始化。这很容易静态地保证,除了延迟构建的数组/向量存储中未使用的部分的某些情况。我们可以强制执行两个简单的替代方案(任何一个都足够):

  • 根据要求初始化声明赞成的意见。类型欧洲标准.20; 并且可能会默认为零初始化数据,如当前在第2723页这两个很好,但也有一些缺点;对于需要从未使用过但优化器很难消除的“伪”写入的情况,两者都有一些性能成本,而后者有一些正确性成本,因为它“修复”了一些未初始化的情况,其中零是有效值,但掩盖了其他零不是有效初始化器的情况,因此行为仍然是错误的,但因为零点被塞进了,所以消毒器很难检测到。
  • 有保证的初始化是预使用的,类似于Ada和C#成功完成的操作。这仍然易于使用,但可以更高效,因为它避免了人工“伪”写入的需要,并且可以更灵活,因为它允许为不同路径上的同一对象使用替代构造函数。有关详细信息,请参见:示例诊断;定义首次使用规则.

终身安全

强制执行赞成的意见。终身安全简介默认情况下,禁止手动分配,并保证空检查。Lifetime配置文件是一种静态分析,可以诊断许多常见的悬空和无需使用的源,包括迭代器和视图(不仅仅是原始指针和引用),其效率足以在编译期间运行。它可以作为迭代和进一步改进的基础。我们还应保证:

  • 默认情况下禁止所有手动内存管理(new、delete、malloc和free)。推论:默认情况下禁止“拥有”原始指针,因为它们需要删除或释放。请改用RAII,例如通过调用make_unique或make_shared。
  • 所有取消引用均为空。编译器对形式为*p或p->的每个表达式注入一个自动检查,其中p可以与nullptr进行比较,从而对调用位置的所有引用进行null检查(类似于上面的边界检查)。当发生冲突时,可以使用全局null冲突处理程序自定义所采取的操作;一些程序将要终止(默认),其他程序将要记录并继续,抛出异常,与特定于项目的关键故障基础设施集成。

注:当针对已经捕获空解引用的平台(例如将内存不足的页面标记为不可寻址的平台)时,编译器可以选择不发出此检查(并且不执行从该检查中受益的优化)。一些C++特性(如delete)总是进行调用端空值检查。

减少未定义的行为和语义错误

在策略上,减少一些未定义的行为(UB)和其他语义错误(陷阱),以便我们能够自动诊断甚至修复已知的反模式。并非所有UB都是坏的;任何以表演为导向的语言都需要一些。但我们知道,程序员的意图明确,任何UB或陷阱都是一个明确的错误,因此我们可以做以下两件事之一:

(A–好)让陷阱成为一个诊断错误,零误报-每个违规都是一个真正的错误。上面提到的两个示例是自动检查a[b]是否在边界内,*p和p->是否为非空。

(B–理想)让代码真正做到程序员想要的,零误报,即通过重新编译来修复它。在最近的ISO C++2023年11月会议上讨论过的一个例子是,默认为隐式返回*this;当程序员为其类型C编写赋值运算符时,该运算符返回C&(注意:类型相同),但忘记编写返回语句。今天,这是未定义的行为。但很明显,程序员的意思是返回*这个;-没有其他东西是有效的。如果我们退货*这个;默认情况下,所有意外忽略返回的现有代码不仅是“不再是UB”,而且保证会做正确和预期的事情。

(A)和(B)的示例是为了支持链式比较,这使得数学上有效的链能够正确工作,并在编译时拒绝数学上无效的链。现实世界的代码编写这样的链是偶然的(参见:【a】 【b】 [中] [日] [英] 【f】 [克] [小时] [一] [j] [克]).

  • 对于(A):我们可以拒绝所有数学上无效的链,如A!=编译时b>c。这会自动诊断现有代码中试图执行这种无意义链的错误,并且准确无误。
  • 对于(B):我们可以修复所有现有的代码,这些代码编写了类似0<=index<max这样的可能正确的链。现在,这些代码可以静默编译,但完全是错误的,我们可以让它们表示正确的东西。只需重新编译现有代码,即可自动修复这些错误。

这些例子并不详尽。我们应该查看标准中的UB列表,以获得可以自动修复(理想情况下)或诊断的更彻底的案例列表。

总结:C的更好默认值++

C++可以在默认情况下启用安全规则,从而使代码:

  • 完全类型安全,
  • 完全安全,
  • 完全初始化安全,

对于终身安全,这是四种安全中最难的,我预计这些类别中的剩余漏洞主要存在于:

  • 完全零安全,
  • 完全没有原始指针,
  • 使用生命周期安全静态分析诊断最常见的指针/迭代器/视图生命周期错误;

最后:

  • 使用较少未定义的行为,包括通过重新编译默认启用安全的代码来自动修复现有的错误。

所有这些都是可以有效实施的,并且已经实施。大多数Lifetime规则都是在Visual Studio和CLion中实现的,我正在原型化C++的概念验证模式,该模式默认在我的cppfront编译器以及其他安全改进,包括实施ISO C++合同的当前提案。我还没有大规模使用原型。然而,我可以报告,我从早期用户收到的第一个主要更改请求是将边界检查和空检查从opt-in(默认为off)更改为opt-out(默认为on)。

注:请不要因为cppfront使用C++的实验性替代语法而分心。这是因为我还想看看我们是否能达到第二个正交目标:使C++语言本身更简单,并且不需要教授大约90%的与语言复杂性和怪癖相关的C++指导文献。然而,本文的语言安全改进与此正交,可以同样应用于当今的C++语法。

解决方案需要区分(A)“新的或可更新代码的解决方案”和(B)“现有代码的解决方法”

(A) “新的可更新代码解决方案”意味着为了帮助现有代码,我们必须更改/重写代码。这不仅包括“(重新)用C#/Rust/Go/Python/…编写”,还包括“用SAL公司“或”更改代码以使用std::span。“

(A)的成本之一是,每当我们编写/更改代码来修复错误时,我们也会引入新的错误;变化从来都不是免费的。我们需要认识到,将我们的代码更改为使用std::span通常意味着非私有地重写它的某些部分,这也可能会产生其他错误。即使注释我们的代码,也意味着编写可能有错误的注释(这是我见过的大规模使用的注释语言(例如SAL)中的常见经验)。所有这些都是重大的采用障碍。

事实上,改用另一种语言意味着失去一个成熟的生态系统。C++是一条老生常谈的道路:它是被教授的,人们知道它,工具存在,互操作工作,当前的法规围绕着C++有一个行业(例如功能安全)。至少要再过十年,另一种语言才能成为一条成熟的道路,而更好的C++及其对整个行业的好处可能会更快出现。

(B) “现有代码的解决方案”强调了无需手动更改代码的可采用性优势。它包括任何可以通过“只需重新编译”使现有代码更安全的内容(即,没有二进制/ABI/链接问题;例如,ASAN、启用堆栈检查的编译器开关、只产生正确结果的静态分析,或可靠的自动化代码现代化器)。

无论新语言或新C++类型/注释多么成功,我们仍然需要(B)。并且(B)具有更容易采用的强大优势。要使CVE减少98%,需要(a)和(B)两个条件,但如果我们仅使用(B)就可以实现30%的减少,这将是采用CVE的主要好处,并对难以更改的大型现有代码库产生有效影响。

考虑一下本附录前面的想法如何映射到(A)和(B):

在C++中,默认情况下强制…(A) 新代码/更新代码的解决方案(可能需要更改代码-无链接/二进制更改)(B) 现有代码的解决方案(只需要重新编译-无需手动更改代码,无需更改链接/二进制)
类型安全禁止所有固有的不安全类型转换使用安全的替代方案进行不安全的转换
约束安全性禁止指针算法禁止未经检查的迭代器算法检查所有允许的迭代器算法的边界检查所有下标操作的边界
初始化安全要求初始化所有变量(在声明时或首次使用之前)
终身安全静态诊断许多常见的指针/迭代器生存期错误情况检查所有指针引用的非空
较少未定义的行为静态诊断已知的UB/错误案例,以在现有代码中的实际错误上出错,只需重新编译一次,误报为零:
禁止数学上无效的比较链
(添加UB附录审查中的其他案例)
自动修复已知的UB/错误案例,使现有代码中的当前错误实际上是正确的,只需重新编译和零误报:
定义数学上有效的比较链
默认返回*this;对于返回C的C赋值运算符&
(添加UB附录审查中的其他案例)

通过优先考虑可采用性,我们可以通过重新编译现有代码至少获得一些安全好处,并使总体改进更容易部署,即使需要代码更新。我认为这使它成为一个值得追求的宝贵战略。

最后,请再次查看主要帖子的结论:行动呼吁.

有效并发:4月在线直播课程

我通常一年上一两门C++和相关技术的课程。今年4月22日至25日,我将进行为期四天半的在线在线公开课程,主题是C语言的高性能低延迟编码++ — 提前注册折扣在本周四之前还有几天可以使用:

与Herb Sutter的有效合作

通过并发和并行实现高性能和低延迟代码

2024年4月22日至25日,每天14:00–18:00 CEST

本强化课程的参与者将获得使用现代C++在当今现代系统上编写高性能和低延迟代码所需的知识和技能。演示者阿尔法软.

有关详细信息和将要涵盖的主题的教学大纲,请参阅课程链接。

该时间旨在对欧洲、中东和非洲地区任何地方的与会者的家乡时区以及美洲的早起者友好。如果你生活在这样一个时代不适合你的地方,并且你想要一个对你的家乡时区更友好的课程,请电子邮件:Alfasoft让他们知道!

因为“高性能低延迟”是C++的一项重要功能,而且因为这是我的课程,所以您会毫不惊讶地了解到,主题和代码都集中在C++上,并涵盖了现代C++17/20/23的功能。但我们毕竟是多才多艺的人……所以不要太惊讶,我有时会用其他流行语言展示一些代码示例,如果只是为了比较和展示另一半的生活方式的话。

行程报告:秋季ISO C++标准会议(美国HI科纳)

今天,ISO C++委员会完成了在美国HI科纳举行的第二次C++26会议。

我们的东道主Standard C++Foundation和WorldQuant为我们周一至周六的六天会议安排了高质量的设施。我们有170多名与会者,其中约三分之二是当面出席,其他人则通过Zoom远程出席,正式代表21个国家。此外,在每次会议上,我们都会有以前从未参加过的新与会者,这一次有十几位新的首次与会者,大多数是亲自参加的;所有人,再次欢迎!

委员会目前有23个活跃的小组,其中大多数在一周内以平行的方式会面。一些小组一周都在跑步,另一些小组则根据他们的工作量,跑几天或一天或一晚上的一部分。您可以找到ISO程序的简要摘要在这里.

本周会议:C++26第2次会议

在6月的上一次会议上,委员会通过了C++26的前40个修改建议,其中包括许多已经准备好召开几次会议的修改建议,而这些修改只是等待C++26train的开通。有关这些亮点,请参见上次跳闸报告.

这次,委员会采用了C++26的下一组特性。它还在其他功能方面取得了重大进展,这些功能现在有望在C++26中及时完成,包括合同反射.

以下是一些亮点…

C++26采用:核心语言更改/功能

核心语言采用了四篇论文,包括P2662R3“组件索引”通过科伦蒂·贾博特巴勃罗·哈尔珀正式添加对使用的支持[识别码]订阅可变参数包。以下是该文件中的一个示例,该示例现在将合法化:

模板<类型名。。。时间>constexpr auto first_plus_last(T…值)->T…[0]{返回T…[0](值…[0]+值…[sizeof…(值)-1]);}int主(){static_assert(first_plus_last(1,2,10)==11);}

对于那些对编写标准提案感兴趣的人,我建议看一下这个及其两个前身P1858和P2632以及写得很好的论文:早期的论文深入研究了激励性用例,本文详细讨论了考虑的其他设计备选方案,以及为什么选择这个。只看到温度…[0]事后很容易称之为“显而易见”,但这远非唯一的选择,本文的分析显示了对备选方案的透彻考虑,包括它们对现有和未来代码以及未来语言进化的影响。

C++26采用:标准库更改/功能

标准图书馆通过了19篇论文,包括以下…

最大的奖项,也可能是本次会议因“提案制定时间最长”而获得的奖项P1673R13,“基于BLAS的自由函数线性代数接口”通过Mark Hoemmen、Daisy Hollman、Christian Trott、Daniel Sunderland、Nevin Liber、Alicia Klinvex、Li-Ta Lo、Damien Lebrun-Grandie、Graham Lopez、Peter Caday、Sarah Knepper、Piotr Luszczek、,蒂莫西·科斯塔,在的帮助下Bob Steagall、Guy Davidson、Andrew Lumsdaine、和戴维斯·海岭。如果你想做有效的线性代数,你不想手工编写自己的代码;那会很慢。相反,您需要一个针对您的目标硬件体系结构进行调优的库par_unseq矢量化算法,速度极快。这是那个图书馆。有关详细的基本原理,请特别参阅第5节“为什么在C++标准库中包含密集线性代数?”和第6节“为什么将C++线性代数库建立在BLAS上?”

P2905R2“运行时格式字符串”P2918R2“运行时格式字符串II”通过维克托·兹维罗维奇基于C++20构建格式库,它已经支持编译时格式字符串。现在有了这两篇论文,我们将直接支持编译时未知的格式字符串,并可以选择不进行编译时格式字符串检查。

P2546R5“调试支持”通过雷内·费迪南·里维拉·莫雷尔,基于之前的工作伊莎贝拉·穆尔特在里面第1279页,添加了标准::断点(),标准::断点_if_debugging()、和标准::is_debugger_present()这将现有技术标准化,这些技术已经在Amazon Web Services到Unreal Engine等环境中可用,使用通用标准API,程序员可以对断点进行完整的运行时控制,包括(引用本文):

  • “允许打印出额外的输出以帮助诊断问题,
  • 执行额外的测试代码,
  • 显示额外的用户界面以帮助调试…
  • …当检测到罕见的非关键条件时,发生断裂,
  • 允许在复杂的运行时敏感条件下进行编程控制,
  • 中断用户输入以检查交互程序中的上下文,而无需切换到调试器应用程序,
  • 等等。”

我能立即想到在过去一个月里我会用这个的次数,也许你也能。

这些是一些“更大”的论文作为亮点……还有16篇论文被采纳,包括对C++26语言和标准库的更多扩展和修复。

正在瞄准C++26:合同

合同小组SG21决定了在C++26中土地合同需要回答的几个长期未决问题。也许不是最重要的,但最明显的是合同语法:本周,SG21批准追求P2961R2“合同的自然语法”通过延斯·莫勒蒂穆尔·多姆勒作为C++26契约的语法。主要可见的变化是,不是像这样写合同:

//以前的语法草案整数f(整数i)[[预:i>=0]][[后r:r>0]]{[[断言:i>=0]]返回i+1;}

我们将这样写,将“assert”改为“contract_assert”……几乎每个人都喜欢“assert断言宏:

//新采用的语法整数f(整数i)预(i>=0)帖子(r:r>0){合同资产(i>=0);返回i+1;}

我已经在我的cppfront前部编译器,它使用前一个[[ ]]语法(因为,当我没有更好的语法时,我会尝试使用现有/建议的C++中的语法)。因此,一旦P2961在周二上午获得小组批准,我决定在周二下午实现对该语法的更改,但我保留了这个好词“断言“因为我可以做到这一点,而不需要对我的实验替代语法进行彻底的更改。这项工作最终花费了不到一个小时的时间,包括更新repo自己的代码,我自己在编译器及其单元测试中使用契约。您可以查看中的差异这些|提交。作为一名早期合同用户,我最初的个人反应是,我喜欢这个结果。

还有一些设计问题需要决定,特别是隐式lambda捕捉的语义,康斯坦瓦尔和多个声明。从现在到明年3月在东京举行的下一次会议,已经安排了六次合同电话会议。该小组的目标是向东京提交一份功能完整的提案,以提交给其他小组审查。

今天,当向全体委员会报告这一进展时,大家都报以掌声。应该是这样的,因为本周的进展增加了人们对该特性在C++26上运行的信心!

请注意,“对于C++26”并不意味着“还有三年的时间,也许我的孩子有一天可以使用它。”已完成在接下来的18个月左右的时间里,一旦它完成,就可以发布实现,从而能够自信地实现它。我们很可能会更快地看到实现,就像我们对其他流行的需求草案标准功能所做的那样。

谈到取得巨大进展的主要功能,本次会议将满怀信心地步入C++26的轨道…

瞄准C++26:反思

反思小组SG7看到了积极使用Lock3 Software P2996原型实现的人员的两份经验报告:P3010R0“使用反射替换生成JS绑定的元语言”通过丹·卡茨、和P2911R1“具有基于值反射的Python绑定”通过亚当·拉赫杰格鲁特·戴夫正如你从标题中看到的,这些都是认真尝试对主要用例进行反射的尝试。两份经验报告都支持P2996R1,因此…

随后,该集团一致投票通过P2996R1“C++26的反射”通过怀亚特·奇尔德斯、彼得·迪莫夫、巴里·瑞文、安德鲁·萨顿、费萨尔·瓦利,达维德·范德沃德并将其转发给针对C++26的主要Evolution和Library Evolation子组。这是一个静态反射的“核心”,足以解决许多重要问题,同时也让我们计划在C++26之后继续在此基础上进行构建。

这对我个人来说尤其令人兴奋,因为我们迫切需要在C++中进行反思,基于本周的进展,现在是我第一次有足够的信心提到这一极其重要的功能的目标船载具。

也许反射最常见的例子是“枚举到字符串”,下面是这个例子:

模板<类型名E>需要std::is_enum_vconstexpr std::string enum_to_string(E值){模板(constexpr auto e:std::meta::members_of(^e)){如果(值==[:e:]){返回标准::字符串(标准::元::名称of(e));}}return“<unnamed>”;}

请注意,上面使用了一些新的反射语法,但这只是实现……新语法仍然封装在那里。使用的代码枚举_字符串对反射一无所知,只需使用函数:

enum颜色{红、绿、蓝};static_assert(enum_to_string(颜色::red)==“red”);static_assert(enum_to_string(Color(42))==“<unnamed>”);

有关更多详细信息,请参阅本文,包括第2.6节中有关枚举到字符串的更多信息。

更令人兴奋的是,爱迪生设计集团注意到他们希望在圣诞节之前在Godbolt编译器资源管理器上有一个实验性的实现。

P2996建立在原始Reflection TS的核心之上,主要更改了我们知道可能会从TS更改的“顶部”和“底部”层:

  • 在“顶层”或编程模型层,P2996避免了必须执行的操作temp<延迟,meta<pro,gram>>::ming使用API,让我们编写更像普通C++代码的代码。
  • 在“底层”实现层,它使用了一种更高效的基于值的实现。

这并不意味着反射TS没有用处;它是工具性的。如果我们没有首先完成TS,那么到这一点的进展会更慢,我们非常感谢为此所做的所有工作,以及P2996作为面向C++26的反射功能的新进展。

在一致通过投票将本文转发给C++26之后,小组中响起了一阵掌声。

然后,今天,当在闭幕全体会议上向全体委员会报告面向C++26的进展时,整个房间里都充满了持续的掌声。

其他进展

本周,许多其他小组继续取得进展。以下是一些亮点…

SG1(Concurrency)将在面对面会议或会议之间的远程通信中,致力于解决放松原子的非即时问题。他们仍在前进的轨道上标准::执行以及C++26的SIMD并行性,SIMD在库进化(LEWG)主要子组中进行了评审;用小组主席的话说,这些特性将使C++26成为并发和并行组的一个巨大版本。

SG4(联网)继续致力于更新std::执行发送方和接收方。还有很多工作要做,还不清楚C++26是否能正常联网。

SG9(Ranges)为C++26的范围设置功能和优先级列表。有些论文需要作者,包括那些对新作者来说很好的“第一篇论文”,所以如果你有兴趣为Ranges的论文投稿,请联系Ranges主席Daisy Hollman。

SG15(Tooling)考虑了关于改进模块以实现更好的工具的论文,并致力于实现第一个C++生态系统标准。

SG23(安全)小组在Bjarne Stroustrup提出的C++安全配置文件方面取得了进一步进展,并将其作为C++安全的近期方向。更新后的论文将在12月中旬的下一次邮件中提供。

库进化(LEWG)开始为新的C++库设置策略框架。该小组还就一些针对C++26的提案取得了进展,包括标准::配置单元,SIMD(矢量单元并行),范围扩展,以及标准::执行以及可能对物理单元的一些支持,所有这些都取得了良好的进展。

语言进化(EWG)致力于改进/转发/拒绝许多建议,包括与C委员会一起讨论改进未定义行为,包括八篇关于预处理器中未定义行为的论文。该小组还决定对编译器目前不需要检测和诊断的“格式不正确、不需要诊断”的未定义行为进行全面审计。我们下一次东京会议的计划是花大量时间进行反思,并为专注于合同做好准备。

感谢所有在所有小组工作了一周的专家,他们在本周取得了如此大的成就!

接下来是什么

我们的下一次会议将在三月的日本东京由丰田Woven主办。

总结

再次感谢参加本周会议现场和在线的170多名专家,以及更多通过国家机构参与标准化的专家!

但我们并没有放慢脚步……我们将继续举行小组Zoom会议,然后在四个月后,我们将再次亲自参加会议,并继续向C++26添加功能。再次感谢大家阅读本文,感谢大家对C++及其标准化的兴趣和支持。

我的新CppCon演讲在YouTube上:“合作C++进化——走向C++的TypeScript”

我周四的CppCon演讲现已上线。

注意:有已经有一个Reddit线程了,所以如果你想评论视频,我建议你使用这个线程,而不是创建一个新的线程。

在2022年CppCon上,我为我们为什么应该尝试使C++10倍简单,50倍安全,这个更新是我五月份在C++Now上所做的更新演讲的演变,还有其他新闻和演示。

“飞镖计划”和“TypeScript计划”

本演讲的后半部分明确区分了我所称的“Dart计划”和“TypeScript计划”,旨在将现有流行语言提高10倍。这两个计划都有价值,但它们有不同的优先级,因此选择了不同的约束……最重要的是,它们要么预先接受完美的C++互操作和生态系统兼容性或者他们放弃它(永远;正如我在演讲中所说的,它永远不可能追溯到过去,除非重新开始,因为这是一个基本的预先约束)。还没有人尝试过C++的TypeScript计划,我看到了尝试它的价值,所以这就是我在cppfront中遵循的计划。

当人们问我“cppfront与所有其他试图改进/替换C++的项目有何不同?”我的回答是“cppfrint在TypeScript计划中。”所有其他过去和现在的项目都在Dart计划中,这也是一个很好的计划,它只是有不同的优先级和权衡,特别是在以下方面

  • 完全无缝互操作兼容性使用ISO标准C++代码和库,无需任何包装/转换/封送,
  • 完全生态系统兼容性使用当今所有的C++编译器、IDE、构建系统和工具,以及
  • 全面标准演进支持使用ISO C++,包括不创建不兼容的特性(例如,与C++20不同的概念特性、与C++20的不同的模块系统),并将所有主要的新功能引入当今的ISO C++发展中,同时也为当今的C++提供了增量建议。

只看到演讲的最后10分钟我演示了语法2“只是工作”于四个不同IDE的调试器和可视化工具,但我也可以演示分析器只是工作,构建系统只是工作,等等。

我称我的实验语法2(aka Cpp2)为“仍然是100%纯C++”,这不仅是因为cppfront将其转换为今天的100%C++语法(aka C pp1),而且因为:

  • 每个句法-2型一个普通的C++类型,普通的现有C++代码可以使用,它可以被包括IDE可视化工具在内的了解C++类型的工具识别;
  • 每个语法-2函数一个普通的C++函数,普通的现有C++代码可以使用该函数,由了解C++函数的工具(包括调试器)识别;
  • 每个语法-2对象普通现有C++代码可以使用的普通C++对象;
  • 每个语法-2特性都可以(并且已经)作为一个标准的ISO C++标准提案来发展今天的语法,因为Cpp2拥抱并遵循今天的C++标准、指导和发展,而不是与它们竞争;

这是因为我想要一种方法来保持编写100%纯C++,只是更好。

“更好”意味着:更简单10倍,具有更多的通用性和一致性,更好的默认值,更少的仪式;在初始化安全(在Cpp2中得到保证)、类型安全(在Ppp2中获得保证)、边界安全(在Dpp2中默认为打开)和寿命安全(在cppfront中仍然要实现的是我为Cpp2设计的C++核心指南寿命静态分析)这四个方面的漏洞减少了98%,安全性提高了50倍。

Cpp2和cppfront没有代替您的C++编译器。Cpp2和cppfront使用所有现有的C++编译器(以及构建系统、分析器、调试器、可视化工具、自定义内部工具、测试工具,以及已建立的C++生态系统中的所有其他东西,从大型商业公共C++产品到团队的内部定制C++工具)。如果您已经在使用GCC、Clang和/或MSVC,请继续使用它们,它们都可以正常工作。如果您已经在使用CMake或build2,或lldb或Qt Creator调试器,或您最喜欢的分析器或测试框架,请继续使用它们,所有C++工具都能理解的仍然是C++。没有新的生态系统。

只有两个计划可以实现10倍的重大改进。(1分钟片段)这是与我所知的对当今C++进行重大改进的所有其他尝试的根本区别,这些尝试都在Dart计划中,这些都是由真正聪明的人完成的伟大项目,我希望我们都能相互学习。但对于我的工作,我想追求TypeScript计划,我认为这是唯一一个可以合法地称自己为“仍然是100%C++”的主要进化计划。这对我来说很重要,因为就像我去年演讲一开始所说的(1分钟片段),我想鼓励我们追求带来C++本身前进和双下在C上++,而不是切换到其他东西-旨在将主要的C++进化定向到将使我们更好的C++程序员而不是其他东西的程序员。

我首先花时间做这个实验,因为C++是最能让我表达我需要编写的程序的语言,所以我想继续编写真正的C++类型、真正的C++函数和真正的C++其他所有东西……更好。

再次感谢120多人他们为cppfront贡献了问题和公关,还有更多人提供了周到的评论和反馈!我感谢你的帮助。

cppfront:秋季更新

自从2022-12-31年末小型更新2023-04-30春季更新,继续取得进展cppfront前部.(如果你不知道这个个人项目是什么,请参阅CppCon 2022在YouTube上的演讲概述,以及CppNow 2023在YouTube上聊天进行临时更新。)

我会给你最新消息下周在CppCon我希望能在那里见到你们中的许多人!同时,这里有一些关于自春季更新帖子以来发生的事情的注释,包括:

  • 致谢和感谢
  • 已启动自托管
  • 没有留下数据:强制显式丢弃
  • 要求条款
  • 广义别名+constexpr==
  • 安全枚举标记_编号纯理功能
  • 安全联盟元函数
  • 接下来是什么

致谢:谢谢!

谢谢你感谢所有通过公开发行和PR参与cppfront回购的人,以及更多参与PR审查和评论的人!这些贡献者代表了从高中生和本科生到全职教授,从商业开发商到会议发言人,以及除南极洲以外的每一个大陆的人们。

已启动自托管

我还没有花太多时间将cppfront自己的代码从今天的语法1转换为我的备用语法2(我简称为“Cpp1”和“Cpp2”),但我从现在主要用Cpp2编写的所有cppfront's反射API和元函数开始。这是什么反射h2文件编译看起来就像在我笔记本电脑上的命令行上编译时一样:

但请注意,您仍然可以使用任何最新的C++20编译器将cppfront构建为当今的C++,因为我也将源代码作为C++进行分发(就像Bjarne将cfront源代码也作为C进行分发一样)。

没有留下数据:强制显式丢弃

初始化和数据流是安全代码的基础,所以从一开始我就确保语法2保证在使用前进行初始化,我默认情况下使所有转换构造函数显式……我将[[nodiscard]]作为返回值的默认值(1分钟通话片段).

我对[[nodiscard]]思考得越多,就越坚定地认为数据决不能无声无息地丢失,而数据丢失操作应该是明确的。所以我决定尝试一个积极的实验:

  • 使“nodiscard”成为土地的法则,始终隐式要求,没有选项…
  • 调用现有C++库时包括(包括标准::)它们的返回值从未被设计为[[nodiscard]]!

现在,我并不是完全疯了:看看设计说明:显式丢弃有关我如何第一次调查其他语言的设计者对其语言(尤其是C#、F#和Python)的体验的详细信息。特别是,F#对做了同样的事情。NET API-F#需要显式|>忽略丢弃未使用的返回值,包括for。NET API,这些API从来都不是为此而设计的,大部分是用其他语言编写的。唐·赛姆告诉我,这并不是一个重大的痛点,这很鼓舞人心,所以我也在效仿。

到目前为止,我的经验是,这是非常轻松的,我为每200行代码写了一个显式丢弃,即使是在使用C++标准库时(cppfront普遍这样做,因为C++标准库是只有cppfront使用的库)。到目前为止,每次cppfront告诉我必须写一个显式丢弃,我都学到了一些有用的东西(例如,在此之前,我从未意识到放回(emplace_back)开始退货自C++17以来!push_back仍然不能)我发现我喜欢我的代码显式地自我记录,它没有查看输出值……我的代码看起来更好。

显式丢弃的方法是将结果分配给“don't care”通配符。它不引人注目,但明确而清晰:

_=向量模板_返回(1,2,3);

现在,所有Cpp2编写的C++函数都以[[nodiscard]]的形式发出,除了赋值操作符和流操作符,因为这些操作符是为链接而设计的,每个链总是以丢弃的返回结束。

整个语言结合得很好:显式丢弃与输入输出外面的参数,而不仅仅是返回值。如果您有局部变量x个并将其传递给输入输出参数,如果这是变量的最后一次使用呢?

{x:=my_vector.begin();标准::提前(x,2);//错误,如果参数是Cpp2'inout'或Cpp1 nonst'&'}

在本例中,调用std::前进(x,2);肯定是最后一次使用x个,因此Cpp2将自动通过x个作为一个极值,并使其成为移动候选……马上!调用无法编译因为你不能把rva值传递给Cpp2输入输出参数(与Cpp1非测试相同-&参数,这样在调用引用非静态的现有C++函数时,也可以正确检测输出副作用)。这是一个功能,而不是一个错误,因为如果这是最后一次使用x个这意味着函数没有考虑x个同样,它忽略了标准::提前(x,2)函数调用,这与忽略返回值非常类似。指导原则是一样的:如果你真的打算这么做,只需显式地放弃x个的最终值:

{x:=my_vector.begin();标准::提前(x,2);_=x;//好吧,你说你是认真的,那么继续。。。}

正在添加_=x;之后自然制造那个最后一次使用x个而不是。问题解决了,它自我记录了代码实际上意味着忽略函数的输出值。

我真的非常喜欢我的C++代码的数据流在语法2中是如何显式的、完全受保护的和安全的。我很高兴看到它在整个语言中是如何自然地工作的——从通用保证初始化,到默认的显式构造函数,到禁止隐式丢弃任何值,到统一处理返回值,无论是返回值还是输入输出外面的参数,并且所有这些参数都可以与现有的C++库一起使用,因此从语法2中使用它们更安全、更好。数据总是初始化的,数据永远不会无声地丢失,数据流总是可见的。数据是宝贵的,而且总是安全的。这对我来说是正确的。

要求条款

我还添加了对要求子句,所以现在可以在所有模板上编写这些语句。cppfront实现已经生成了一些requires子句(请参见这个1分钟的视频剪辑)。现在程序员也可以自己编写了。

这需要与GCC 10中关于声明的requires-clauses的错误进行一些斗争,该错误在GCC 11+中得到了修复,但从未被反向移植。但因为这是我在GCC 10中遇到的唯一一个我无法回避的问题,而且因为我可以给出一个明确的诊断,即GCC 10不支持Cpp2中依赖requires子句的一些功能,到目前为止,我已经能够保留GCC 10作为一个受支持的编译器,并且如果您尝试使用它不支持的少数功能,则可以发出诊断。GCC 11和更高版本都很好,支持所有Cpp2语义。

广义别名+constexpr==

在4月份的博客文章中,我提到我需要一种方法来编写类型和名称空间别名,因为所有的Cpp2声明都是这样的thing:type=值,我决定尝试使用相同的语法,但==表示“始终等于”

//命名空间别名lit:namespace==::std::literals;//类型别名pmr_vec:<T>类型==标准::vector<T,标准::pmr::polymorphic_allocator<T>>;

我认为这清楚地表明点燃始终与::std::文字、和pmr_vec<整数>始终与标准::vector<int,标准::pmr::polymorphic_allocator<int>>.

从那以后,我一直在思考如何将其最好地扩展到功能和对象,我意识到这些需求似乎与我需要支持的其他东西重叠:常量表达式函数和对象。毕竟,这些函数/对象在编译时返回/具有“始终相同的值”…

//具有“始终相同的值”的函数(constexpr函数)增量:(value:int)->int==value+1;//Cpp2允许在单线体周围省略{return}//具有“始终相同值”的对象(constexpr对象)四十二:i64==42;

我特别需要这些来写枚举元函数…

安全枚举标记_编号纯理功能

春季更新博客帖子,我描述了我在cppfront中实现的前10个可运行的编译时元函数,它们来自我在中描述的元函数集我的ISO C++论文P0707。从那时起,我还实施了枚举联盟.

关于元函数最重要的一点是,它们是使用反射和代码生成API的编译时库代码,它允许普通C语言的作者++类型可以很容易地选择一组命名的默认值、需求和生成的内容。这种方法对于简化语言至关重要,因为它可以避免将特殊的“额外”类型硬连接到语言和编译器中。

在Cpp2中,没有枚举硬连接到语言中的功能。相反,您只需编写一个普通类类型并应用枚举元函数:

//skat_game声明为安全枚举类型:它具有//默认/复制/移动构造/赋值和<=>//std::strong_ordering,一个最小大小的有符号基础类型//默认情况下,如果用户未指定类型,则无隐式//转换到基础类型/从基础类型转换,实际上没有公共//除了复制构造之外的构造,这样它就永远不会//具有与其列出的内联枚举器不同的值//具有自动启动的值的constexpr枚举器//为1,如果用户没有自己编写,则增量为1//值和to_string()等便利。。。“枚举”一词//表达了所有这些含义,方便易读//opt-in,没有将“enum”硬连接到语言中//skat_game:@enum类型={钻石:=9;红心;//10黑桃;//11俱乐部;//12grand:=20;空:=23;}

考虑心脏:这是一个成员对象声明,但它没有一个通常非法的类型(或默认值),但这是可以的,因为@枚举<i16>metafunction填充它们:它遍历所有数据成员,并为每个数据成员提供基础类型(这里显式指定为第16页否则,它将被计算为足够大的最小有符号类型)和初始值设定项(默认情况下比前一个枚举数高一个)。

为什么在一个普通的C++类上有这个元函数,而C++已经有了两个C枚举和C++11枚举类? 因为:

  • 它使语言更小、更简单,因为它没有将特殊用途的发散碎片类型硬连接到语言和编译器中
    • (暗示披头士乐队,并且:“你所需要的只是(哇哇,哇哇),你只需要(哇哇,哇哇哇)”);
  • 这是一个更好的枚举大于C枚举,因为C枚举是非范围的,并且不是强类型的(它隐式转换为基础类型);
  • 这是一个更好的枚举类比C++11枚举类,因为它更灵活…

……考虑:由于枚举类型现在“只是一个类型”,它自然也可以具有成员函数和其他Cpp1枚举和枚举类所不可能的东西(请参见这个StackOverflow问题):

janus:@enum类型={过去的;未来;翻转:(在此之外)=={如果this==过去{this=未来;}否则{this=过去;}}}

还有一个标记_编号具有双幂语义和无符号基础类型的变体:

//file_attributes声明为安全标志枚举类型://与枚举相同,但具有最小大小的无符号底层//默认情况下键入,值自动从1开始//如果用户不写他们的//自己的值和按位操作加上.has(标志),//.set(标志)和.clear(标志)。。。单词“flagenum”//表达了所有这些含义,方便易读//无需将“[Flags]”硬连接到//语言//文件属性:@flag_enum类型={缓存;//1当前;//2过时;//4cached_and_current:=缓存|当前;}

安全联盟元函数

并且您可以声明性地选择编写一个安全的歧视联合/变量类型:

//name_or_number是声明性的安全联合/变量类型://它有一个鉴别符,只执行一个选项//可以一次激活,成员总是有名字,并且//每个成员都有.is_member()和.member()访问器。。。//“联合”一词表达了所有方便的意思//和可读opt-in,无需专门硬接线“union”//融入语言//名称或编号:@联合类型={名称:std::string;编号:i32;}

为什么在一个普通的C++类上有这个元函数,而C++已经有了两个C联盟和C++11标准::变量? 因为:

  • 它使语言更小、更简单,因为它没有将特殊用途的发散碎片类型硬连接到语言和编译器中
    • (再次提示披头士耳虫:“就是你所需要的,是您所需要的……”);
  • 这是一个更好的联盟比C联盟,因为C联盟不安全;
  • 这是一个更好的变体比C++11标准::变量,因为标准::变量很难使用,因为它的替代项是匿名的(就像类型本身一样;在类型系统中无法区分变量<int,string>存储员工id或员工姓名,以及变量<int,string>储存幸运数字或宠物独角兽的主要颜色)。

每个@活接头类型有自己的类型安全名称,有清晰明确的命名成员,并安全地封装了一个鉴别器来管理所有成员。当然,它在实现中使用了不安全的强制转换,但它们是完全封装的,可以进行一次测试,并且在所有使用中都是安全的。这使得@工会:

  • 像C一样容易使用联盟,
  • 标准::变量…和
  • 另外,由于它是一个普通类型,它自然可以具有普通类型可以具有的其他内容,例如模板参数列表和成员函数:
//模板化的自定义安全联盟name_or_other:@union类型= {名称:std::string;其他:T;//自定义成员函数to_string:(this)->标准::string={if is_name(){return name();}else if is_other(){将其他()作为std::string;}返回else{返回“无效值”;}}}主:()={x: 名称或其他<int>=();x.set_其他(42);标准::cout<<x.other()*3.14<<“\n”;std::cout<x.to_string();//打印“42”,但无论哪个选项有效,都是合法的}

接下来是什么

在今年剩下的时间里,我计划:

  • 继续自托管cppfront,即迁移更多cppfront's自己的代码以使用Cpp2语法编写,特别是现在我已经枚举联盟(cppfront使用枚举类标准::变量普遍地);
  • 继续处理我的待定Cpp2功能列表并在cppfront中实现它们;
  • 与一些私人alpha测试人员合作,开始用Cpp2编写一些代码,用于alpha-test-cppfront以及alpha-test我的(到目前为止尚未发布的)文档草稿。

但首先,一周后,我会在CppCon公司就这一进展以及为什么与ISO C++的全保真兼容性至关重要(以及这意味着什么)进行讨论:“协同C++进化:走向C++的TypeScript。”我期待着在那里见到你们中的许多人!

我的C++Now 2023演讲在线:“C++的TypeScript”

再次感谢现在使用C++感谢您邀请我今年在美国科罗拉多州光荣的阿斯彭演讲!很高兴在那里再次见到许多老朋友,也结识了一些新朋友。

我在那里的演讲刚刚发布在YouTube上,你可以在这里找到:

在2022年CppCon上,我为我们为什么应该尝试使C++10x更简单、更安全,我展示了我自己的不完整的实验编译器,cppfront前部自那时以来,cppfront一直在不断进步:我的春季更新帖子介绍了类型、反射API和元函数的添加,这篇演讲是在帖子发布一周后进行的,并通过讨论和现场演示展示了这些功能。

本次演讲还明确区分了我所称的“Dart计划”和“TypeScript计划”,旨在将现有流行语言提高10倍。这两个计划都有价值,但它们有不同的优先级,因此选择不同的约束……最重要的是,它们要么正面接受完美的C++互操作兼容性或者他们放弃它(永远;正如我在演讲中所说的,它永远不可能追溯到过去,除非重新开始,因为这是一个基本的预先约束)。还没有人尝试过C++的TypeScript计划,我看到了尝试它的价值,所以这就是我在cppfront中遵循的计划。

当人们问我“cppfront与所有其他试图改进/替换C++的项目有何不同?”我的回答是“cppfrint在TypeScript计划中。”所有其他过去和现在的项目都在Dart计划中,这也是一个很好的计划,它只是有不同的优先级和权衡,尤其是在兼容性方面。

视频描述有一个主题指南,链接到谈话的要点。下面是该主题指南的更详细版本……我希望您喜欢这次演讲!

1点演讲简介和路线图

2:281.cppfront概述

2:35–绿地实验很棒;但cppfront是关于刷新C++本身

3:28–“当我说兼容性时……我的意思是,我可以调用现在存在的任何C++代码……没有填隙符,没有重音,没有开销,没有间接,没有包装”

4:05–无法在不破坏世界的情况下对现有代码进行破坏性更改

5:22–对我来说,C++最具影响力的版本是C++11,它极大地改变了我们编写代码的方式

6:20–如果我们可以再次使用C++11,但需要一组协调的功能来内部演化C++

6:52–cppfront是一个正在进行的实验,尚不完整

7:41–感谢100多位cppfront贡献者!

8:00–2022年CppCon上演示的功能摘要幻灯片

–C++的安全性;由于类型/界限/寿命/初始化安全,目标是减少50倍的CVE

–C++的简单性;目标是少知道10倍

10:00– 2. cppfront:新增功能

10:05–(a)3个较小的新功能,显示出简单性+安全性+效率

10:15–这项工作已经标准化

11:05–简单、安全和效率很少紧张,有正确的抽象

12:55–链式比较:简单、安全(数学上)、高效(单一评估)

15:08–命名循环/break/continue:简单、安全(结构化)、高效

16时51分–main的参数:simple(std::always available)、safe(默认为bounds/null check)、effective(仅当您要求main参数时才支付)

18:30–(b)用户定义的类型

19:20–显式`this`

20时20分–默认值:很少写入访问指定项

21:30–(回想一下CppCon 2022:带“out”参数的可组合初始化安全性)

23:50–统一`operator=`:{构造,赋值}x{copy,move}是单个函数(默认情况下)

25:48–统一`operator的可视化=`

27分28秒–为unified`operator生成示例代码=`

31:35–virtual/override/final是“this”的限定符`

35:05–演示:继承(这次是GCC)

40:43–复活节彩蛋

41:55–可以交错基础和成员,对布局和寿命有更多控制

43:10–(c)反射和类型元函数

43:10–回顾2017年CppCon的概述

54:23–演示:应用类型元函数

56:10– 3.兼容性对于C++

56分35秒–John Carmack谈现实世界中的兼容性

59:40–回顾:“Bridge to NewThingia”演讲摘要

1:02:05–避免采用步骤功能需要高保真兼容性

1:04:25–C++来自C,TypeScript来自JavaScript,Swift来自Objective-C,Roslyn来自先前的编译器

1:05:45–强调并剖析TypeScript的兼容性故事

1:07:55–飞镖:目标相似,但不是为了兼容而设计的,如果不重新开始,你将永远无法恢复兼容性

1:08:55–不兼容花费十年时间的原因示例:

1:08:57––VC++6.0至10.0…12年

1:10:28––Python 2到3…12年(Python's#1姊妹语言)

1:18:30––C99至C11…12年

1点18分50秒––C++11 basic_string(2008年批准)至2019年在所有主要平台上提供支持……11年

1:19:25–“失落的十年”模式:缺乏无缝兼容性将使您损失十年的采用时间

1:20:45–三个“计划”:“10%计划”、“飞镖计划”和“TypeScript计划”

1:21:00–“10%计划”:增量演变

1:21:40–那么我们如何实现10倍的改进?

1:21:50–“飞镖计划”:设计新的东西,不担心兼容的互操作,有竞争力

1:23:20–“TypeScript计划”:设计兼容、合作的内容

1:25:40–如何兼容地发展C++,这是其他任何努力都没有尝试过的

1:28:50–填写空白:______代表C++

行程报告:夏季ISO C++标准会议(保加利亚瓦尔纳)

几分钟前,ISO C++委员会完成了在保加利亚瓦尔纳的会议,并通过Zoom在线,我们正式开始在C++26中采用功能。

我们的东道主VMware和Chaos为周一至周六的六天会议安排了高质量的设施。我们有近180名与会者,其中约三分之二是当面出席,其他人则通过Zoom远程出席,正式代表20个国家。此外,在每次会议上,我们都会有以前从未参加过的新与会者,这一次有17名新的首次与会者,大多数是亲自参加的;所有人,再次欢迎!

委员会目前有23个活跃的小组,其中大多数在一周内以平行的方式会面。一些小组跑了一周,另一些小组跑了几天或一天和/或晚上的一部分时间,这取决于他们的工作量。您可以找到ISO程序的简要摘要在这里.

本周会议:启动C++26

ISO C++的开发周期为三年,其中包括大约在发布和发布该版本标准之前一年的“功能冻结”。例如,C++23的特性冻结是在2022年初。

但这并不意味着我们在这个周期中只有两年的开发时间,第三年是错误修复和繁文缛节。相反,子组是三级管道并继续同时进行新功能开发,而功能冻结只是我们暂停加载新功能的检查点这个特别的火车。因此,在过去的一年中,随着小组完成了C++23特性的fit-and-fish工作,他们也越来越多地致力于C++26特性。

这表明,本周我们通过了首批40份提议的C++26更改文件,其中许多文件已经准备好举行几次会议,正在等待C++26列车开放供装载通过。在这40份变更文件中,有两份是“为所有就绪问题应用决议”,其中应用了一系列一般性变更。其他38个是单独的更改,从错误修复到危险指针和RCU等新功能。

以下是一些亮点…

C++26采用:核心语言更改/功能

核心语言通过了11篇论文,包括以下内容。按照纸的编号顺序来计算,这大致是纸上工作开始的顺序…

P2169“一个没有名字的漂亮占位符”通过科伦蒂·贾博特和迈克尔·帕克正式添加对_C++26中的通配符。感谢作者们的所有研究和证据,它们证明了如何以向后兼容的方式实现这一目标!随着编译器开始支持draft-C++26语法,下面是一些合法的示例:

std::lock_guard(互斥);

自动[x,y,_]=f();

检查(foo){_=>bar;};

一些编译器需要实现-旺德巴.

回文P2552“关于标准属性的可忽视性”通过蒂穆尔·多姆勒阐述了机器人学的三条定律……呃,我的意思是,标准属性的三条可忽略性规则。三条规则是所有当前和未来标准属性的语言设计指南……完整规则见论文,但我的非正式总结是:

  • [已经在C++23]规则1中。标准属性必须是可解析的(即不能只包含随机的无意义内容)。
  • [已经在C++23中]规则2。删除标准属性并不能改变程序的含义:它可以减少程序可能的法律行为,但不能创造新的行为。
  • [新]规则3。功能测试宏不应假装支持属性,除非实现实际实现了属性的可选语义(即,不仅解析它,而且忽略它)。

P2558“添加@,$、和`到基本字符集“通过史蒂夫·唐尼不是因为诅咒而修改名字的报纸;它是一篇遵循C语言发展轨迹的语言扩展论文,允许在有效的C++程序中使用这些字符,并可能在未来的C++语言发展中使用。

P2621“UB?在我的lexer中?”通过科伦丁·贾博特消除了仅仅对C++代码进行标记化就可能成为C++编译器本身未定义行为的来源的可能性。(你知道它可能是UB吗?现在它不可能了。)但是请注意,这并没有在编译期间删除所有可能的UB;未来的论文可能会讨论更多编译时UB源代码。

P2738“constexpr cast from void*:朝向constexpr-type-erasure”通过科伦蒂·贾博特和大卫·莱杰向强大的编译时库迈出了另一步,包括启用标准::格式潜在支持常量表达式编译时字符串格式。说到这里…

P2741“用户生成的static_assert消息”通过科伦蒂·贾博特让编译时间统计_断言接受非字符串文本的stringlike消息。例如,流行的{fmt}库(但尚未标准::格式,但请参见上文!)支架常量表达式字符串格式,因此此代码可以在C++26中使用:

static_assert(sizeof(S)==1,fmt::format(“意外的sizeof:应为1,得到{}”,sizeof;

与P2738一起标准::格式现在,使用上述两个功能的统计_断言.

C++26采用:标准库更改/功能

标准图书馆通过了28篇论文,包括以下内容。从最低纸号重新开始…

第一个获得“工作时间最长”奖(只需查看论文编号和R修订号):P0792R14,“function_ref:A type-rased callable reference”通过维托里奥·罗密欧、袁志浩和贾拉德·滑铁卢添加function_ref<R(参数…)>作为具有引用语义的词汇表类型,用于将可调用实体传递到标准库。

P1383“<cmath>和<complex>的更多constexpr”通过奥利弗·罗斯滕添加常量表达式到100多个标准库函数。让越来越多的标准库在编译时可用的进程仍在继续……杰森·特纳(Jason Turner)在某处说“Moar Constexpr!”和“Constexpr all things!”

然后,仍然按照纸的编号顺序,我们进入“独立组”:

P2510“格式化指针”通过马克·德·韦弗允许指针值的良好格式,而无需插入重新解释广播首先转换为整数类型。例如,现在这将起作用:格式(“{:P}”,ptr);

P2530“C++26的危险指针”通过Maged M.Michael、Michael Wong、Paul McKenney、Andrew Hunter、Daisy S.Hollman、JF Bastien、Hans Boehm、David Goldblatt、Frank Birbacher和Mathias Stearn添加了Concurrency TS2危险指针功能的子集,以向C++26添加基于危险指针的延迟清理。

P2545“可读副本更新(RCU)”通过保罗·麦肯尼(Paul McKenney)、迈克尔·王(Michael Wong)、马吉德·迈克尔(Maged M.Michael)、安德鲁·亨特(Andrew Hunter)、黛西·霍尔曼(Daisy Hollman)、JF Bastien、汉斯·博姆(Hans Boehm)、大卫·戈德布拉特(David Goldblatt)、弗兰克·伯巴赫(Frank Birbacher)、埃里克·里克托普(作为在C++26中进行延迟清理的另一种补充方式。

P2548“可复制功能”通过迈克尔·哈瓦添加可复制的替换项std::函数,建模于move_only_function(仅移动函数).

P2562“constexpr稳定排序”通过奥利弗·罗斯滕允许在编译时使用标准库的稳定排序(stable_sort(稳定_排序),stable_partition(稳定分区),就地合并、和范围::版本)。杰森·特纳可能在说“莫尔!”…

P2641“检查联合替代方案是否有效”通过巴里·雷维辛和达维德·范德沃德介绍了consteval bool是_within_lifetime(const T*p)noexcept函数,该函数在特定编译时上下文中工作,以确定第页是指向在其生命周期内的对象的指针,例如检查联合的活动成员,但在开发过程中,该功能变得比仅仅一个用例更有用。(从技术上讲,这是一个核心语言特性,但它位于标准的“magic std::features that look like library functions but actually implemented by the compiler”部分中的一个,在本例中是元编程子句。)

P2757“类型检查格式参数”通过巴里·瑞文支持更多的编译时检查标准::格式格式化字符串。

这些只是被采纳的论文中的12篇作为重点……还有16篇论文被采纳,它们也为C++26标准库应用了更多扩展和修复。

其他进展

我们还采用了C++26计划下一个三年周期。这与C++23的时间表相同,但只是到处都增加了三年,就像C++23的日程与C++20加三年的日程一样。

语言进化小组(EWG)在一周内看到了30篇论文的演示文稿,主要是针对C++26的建议,包括对上述部分进行微调,使其成为本次会议上的C++26。

标准图书馆进化小组(LEWG)专注于推进队列中的“大”论文,这些论文真正受益于面对面的会议。值得注意的是,现在在以下方面达成了设计共识第1928页SIMD,P0876光纤、和P0843就地矢量,这些论文已被转发给图书馆措辞规范小组(LWG),并可能在11月的下一次会议上被C++26采纳。在以下方面取得了更多进展P0447蜂箱,P0260并发队列,P1030路径视图、和P2781常量_v.

库措辞规范子组(LWG)现在正在处理其积压工作,并花费了大量时间迭代标准::执行sub_mdspan(_M)提案(后者于本周获得通过)。

合同小组在针对C++26改进合同语义方面取得了进一步进展,包括就删除构建模式和拥有合同违规处理API达成共识。

并发和并行子组仍在继续推进C++26的std::execution和SIMD并行,用子组主席的话说,这将使C++26成为并发和并行组的一个巨大版本。

感谢所有在所有小组工作了一周的专家,他们在本周取得了如此大的成就!

接下来是什么

我们接下来的两次会议将在11月,美国HI科纳由WorldQuant和标准C++基金会主办,以及3月日本东京由丰田Woven主办。

总结

再次感谢参加本周会议现场和在线的近180位专家,以及更多通过国家机构参与标准化的专家!

但我们并没有放慢脚步……我们将继续举行小组Zoom会议,然后在不到五个月的时间内,我们将再次亲自与Zoom会面,继续为C++26添加功能。再次感谢大家阅读本文,感谢大家对C++及其标准化的兴趣和支持。