深度好文:How to get started in C++!

news2024/11/17 13:36:44

 Datawhale干货 

作者:zclll,推荐:卢雨畋,Datawhale成员

在大家的不懈催更下(hhh),这篇文章终于和大家见面了。对于程序设计、软件开发而言,我都只是一个入门水平而已(也许C++略多一点,但也并不很多)。对任何知识的掌握,都不足以保证完美无缺。那么有什么可以和大家说的呢?我想,只有对一些事物的理解与认知。如何快速地养成一位普通的C++工程师,是培训班应该去做的任务。而我们,应该为成为一名优秀的软件工程师打好基础

这些内容显然不会是无上真理,因为它受限于笔者的有限认知。但至少,做到这些内容,成为比笔者更优秀的C++工程师,还是非常容易的。

最重要的

对于学编程的新手来说,最重要的事情是——先把代码写起来。这件事情对于各个行业来说都很重要,但也许对coding尤为重要。如果说程序员这个行业一定需要一些天分的话,那么最重要的一个,就是有“先把事情搞起来”的执行力。

这意味着,也许你还在犹豫“我应该学什么,用哪本书、学谁的课”,什么时候学,要不要沐浴更衣,要不要择良辰吉日——都不必。就用你手头有的资源,写你想到的东西,先写起来。如果没有合适的,那么在这篇文章中,我会提供一些——但它不会是本篇文章的重点。

C++需要学什么

被问最多的问题是:“有没有推荐的学习路线?”

要解答这个问题,必须要解决几个前置问题:

你得明确,学C++是为了什么为了赶紧找一份不错的工作?为了做有价值的东西?为了做很酷的东西让自己开心?

自己要去做哪个方面的开发是hpc,服务端,嵌入式,量化……还是什么?让我们一个一个来说。

第一点,你的动机决定了你要去做什么。因为人的精力是有限的,你不可能对C++这么辽阔的版图面面俱到。特别是,C++的世界中有一类特别的人——语言律师,他们对复杂的语法规则——你绝不可能了解的那些——如数家珍,但不一定是非常优秀的软件工程师。你需要决定自己要不要成为这样的人。这并没有优劣之分,只是不同的选择。

就像“茴字有几种写法”一样。当然需要有人知道(比如计算机史学家),但如果你希望成为一名优秀的coder的话,显然不是你需要知道的事情。

那么,掌握一门语言需要到什么程度呢?

对语言的掌握

C++是一门非常复杂的语言,与其他语言最大的不同在于,它有一套被称之为“标准”的东西3 。这套标准非常详尽,事无巨细地规定了C++世界中的每一个角落该长什么样子。也正因为如此,C++世界中有一个经典的笑话,关于 “面试者在简历上写了精通C++结果面试官出了一堆元编程打击得面试者无地自容的那些事儿”。

这意味着我们永远都不能够说自己“精通C++”了么?我看并不是。

很多群友都知道,我在自己的简历上的确写了“精通C++”。因为在我看来,自己已经完全满足这个要求了。我能保证做出cpp quiz中的hard题吗?我不能。给我几个超复杂的候选函数,我能搞懂重载决议会pick哪个吗?我不能。

但让这些炫技的东西出现在一个正经项目的代码里,比“不会C++”可怕一万倍。

我能保证的是,对于我们的项目中所涉及到以及可能涉及到的C++知识,我已经掌握了至少99%了。我的精力应该放到如何写出更简洁、低耦合、可复用的代码上去,应该研究如何让我的代码对CPU、缓存更加友好,应该研究各个组件的架构应该如何设计才能从宏观角度提高性能和稳定性……

——而不是让那些超复杂且有害的东西来占据我本就有限的时间

如果一个机制需要非常复杂的语法去实现它,那么相信我,一定有更好的办法。如果你在cr的时候看到了一个完全看不懂的写法,那么相信我,give it a -1.

这是第一点:你必须清楚自己学C++是为了什么。花一些时间做cool的事情来取悦自己没什么不好,但长期来看,你得大体坚持在正确的道路上,才能写出真正很酷的东西。它会是一个从性能、软件工程等角度上都很酷的东西,而并不因为你采取了很先进或很复杂的语法。

先进的语法只有在让代码更简单的时候才是真的先进;复杂的代码只有让更多的代码更简单/性能更高的时候才是合适的复杂。

所以——

比语言更重要的

专业能力

语言永远只是一个工具。

我想大多数人学C++的目的,是因为它容易写出可掌控、高性能的代码,这就意味着语言不是第一性的,它是为了功能而服务。

如果对业务确实有利,那么明天去写Rust又怎么样呢?任何人都不应该抵触在合适的时机选择更合适的语言。C++也许的确更难学,但不要因为学了它而拥有可悲的壁垒。你的领域知识远比语言更重要

所以,你应该去考虑:我要成为一名hpc开发?还是嵌入式开发?还是后端开发?……

只不过你喜欢C++,那么你可以选一些用C++比较频繁的领域,把C++作为你的核心竞争力之一,而不是“一棵树上吊死”。

当然,语言是这一切的基础。所以你首先得把C++学到一个“能写出各类功能代码”的程度,然后就要尽快让领域知识驱动着你去学习和coding。而这并不难。我们预期花多少时间呢?如果你慢慢学,每天学一点,两三个月总够了;如果你把这作为你的主业,那么顶多需要半个月~一个月的时间。

学习方式

关键点就在于,不要把做一件实事的bar想象地太高

最基本的语法都掌握了吗?很好,去学你想要做的那个领域的知识吧!

思考能力

抓住问题的本质

我想,选择C++作为主要语言的人,往往都对高性能有一些执念吧?那么“抓住问题的本质”这件事情简直太重要,太重要了!

比如有些acmer第一次接触到编译期计算,会想到——我靠,那我直接把运行时算的东西挪到编译期不就得了?TLE再也与我无关!

——当然我们知道这是天方夜谭。但我看到过不少人曾有过这样的想法。问题不在于他们没有掌握元编程的正确知识,而是他们未能建立正确的思考模型

比如说, 下列代码段中,虚函数调用是不是必须的?

struct A{ virtual void f(){ ... } };
struct B : A { void f() override { ... } };

{
     A* a = new B{};
     a->f();
}

如果你C++学得多一点,可能会很快反应过来:我可以用CRTP优化掉这个虚调用嘛!

但这件事的本质并不是CRTP,这件事的本质是“运行前就已经有足够的信息”,即使没有CRTP, 也会有ARTP, BRTP,只要是一个图灵完备的语言,就总有技巧消除掉这个开销。

对你来说,最重要的东西不是学会用CRTP,而是“知道什么是理论上可以实现的”。

就像网络工程师常用的“零拷贝优化”一样,即使没有人总结出来这种优化,它也应该是你有能力在业务优化中思考出来的。你不是掌握了一堆兵器,然后在项目上挨个按上去,看看卡不卡得上。而是:如果这个地方理论上可以更好,那么我总能有个技术把它搞了。

我认为, 从这个角度——也就是事物的本质分析问题的能力, 比编程能力要重要很多倍。掌握很多技术可能能让你成为一名还算不错的软件工程师,而掌握从本质角度思考问题的能力,你才有可能成为一名架构师。

在恰当的抽象层上思考问题

这也是非常重要的一种能力,同时也是对软件工程的理解中的一环。就像我们经常说到,XXX对程序员来说是透明的。CPU有乱序发射,编译器有各种优化,这意味着你需要考虑这些东西会不会搞砸你的代码吗?No。所有的优化与变换,首先得是透明的、条件保持的

如果你决定了用 swap 去交换对象,就不用担心它是否因为应用了针对PIMPL的优化、针对POD的优化,而搞砸你的代码。

如果你需要用或者提供一个接口,你所需要关注的全部就是接口的前条件和后条件,不要做跨层的思考。(除非你正打算从数据流的角度优化算法)

成长路径

原则性的(也是最重要的)东西讲完了,让我们来讲讲成长路径。所谓“成长路径”,简单讲就是“我在各个阶段应该学些什么?”,说直白点,就是“我应该往简历上写些什么?”。

首先第一部分,是你的基础能力,这主要是语言能力——毕竟你得先把想到的东西写出来,才有别的东西可谈。

所以,开始把代码写起来吧。

书籍、参考与练习

对于入门来说,有很多书籍是不错的,但它们都比不上找到自己想做的东西,然后一边写一边查。当然,参考书也是有必要的,我会推荐这本:

《CPP Primer Plus》 

这本书的质量据说不错,但我没看过。叶神说过相比之下还不错,我信叶神的(但他好像也没看过)。

然后呢?把这本书(或者其他你觉得不错的)看个差不多,就已经足够去写代码了。现在对你来说最重要的事情,就是找到你的目标领域当中适合入门的toy,写起来。

请坚决摒弃上学时期张嘴等老师“喂饭”的思维,真正的学习绝不是把书一本一本的读下去就有效果的!

在这个过程中,你需要同步提高自己的C++水平,那么有这两本非常不错的书

  • 《现代C++32讲》

  • 《Effective Modern C++》

后者我更推荐互联网上的gitbook版本,看着更舒服。

如果你需要检验一下自己对C++语法的掌握如何,那么你可以在这里找到很多练习:

Cpp Quiz 

请注意,不要痴迷。你不需要花费时间在这里的Hard难度上。

而如果你需要确定地查找一个关于C++语法与库的正确答案,请到这个对于Cpper最重要的网站:

cppreference.com 

这时候,你就开始需要接触一些C++的最佳实践了:

StackOverflow —— 这个地球上最高质量的程序员问答平台之一 

CppCon —— C++的前沿发展汇报 

总结来说,对于绝大多数新生代的C++ coder(或是其他门类的软件工程师)来说,在学习过程中最需要树立的一个观点是:绝对不是已经掌握了对应的技能才去做东西,你要做一个东西,正是因为你还不会它。

当然,这时候,写出更好的代码就已经不能只局限于使用更合适的语法了,而是必须要从软件工程的角度重新思考你的代码。

重构

最好的方法,就是定期重构自己的代码。重新去思考能不能用更好的抽象,能不能更好地复用?更好的解耦合?

隔一段时间回头看,总会觉得自己的代码像依托答辩,那么,这就是你提升的时候了!

请不要忘记……

能够实际做一些东西,总比纸上谈兵要好,不是吗?

所以一定不要忘了,学会Linux、Cmake、gtest、、git、perf、valgrind、benchmark……这些工具的使用!

那么,我该怎么去学它们呢?在什么时机去接触呢?

答案是当你意识到你需要的时候。 请再次提醒自己,写代码已经不是中学时期等老师来喂你知识的时候了,你必须自己进行思考当你思考如何改进自己的代码的时候,这些工具就会自然进入到你的世界。——这种学习的过程,将会伴随你的整个职业生涯。

如果你说,我写了很多代码(xcpc coding除外),但是仍然好像没有接触到这些工具的使用?那么,这就是你的问题了,其他人无能为力。的确有的人不具备主动思考和学习的能力,那么你要做的应该是关闭这篇文章,去找个培训班让他们想办法帮你物色一个好的工作。

项目

哦,到了大家(中的很多人)最为关心的部分了!所以我把这一小项提升为一个章节来说——

其实人的眼界和机遇,比我们想象当中重要太多了对于绝大多数人来说,无论你找到的工作是什么样的,这个世界上几乎一定存在着更轻松、待遇更优渥的另一个,只是你无法发现。所以多去拓展消息渠道,多接触更优秀的人,对你的意义比想象中的大。至少对我来说,如果大一就能有这样一个QQ群的话,我想自己一定能成长到另一个高度。

所以,好好利用这些资源,去决定自己要做什么。

还是那句话,领域知识才是根本。你要成为一名后端/前端/嵌入式/区块链……工程师,而不是“C++工程师”。

名校Lab

如果说接触商业项目相对困难的话,那么去做lab(课程附带实验)很容易成为你写实际代码的第一步!

这些国外顶尖名校的lab与我们普通大学的实验课有天壤之别,它们往往要求你完成一个非常系统且颇具难度的软件,这其中覆盖了几乎全部这个课程的关键基础知识。因此,它们很适合作为新手入门的第一步。例如以下Lab:

  • CMU 15-445 数据库

  • CMU 15-721 数据库系统进阶

  • MIT 6.824 分布式系统

  • MIT 6.828/s.081 操作系统

  • MIT 6.S191 深度学习

  • ……

当然,随着互联网卷度增加,lab也有“泛滥”之嫌。但相信我,如果你真的搞懂了一个lab,它已经足以让你在对应领域成为一名合格的(校招)工程师了。

开源项目

实际参与开源项目的含金量,我认为不需要我多说了。它远超你的Lab、xcpc牌子、绩点、奖学金……

这对你来说会不会很遥远?我可以告诉你的是,完全不。开源社区中的人们,大多是一群非常友好的家伙,而且非常多的项目都有一些容易让新人上手的case,而且会有很友好的mentor去对应的协助你完成。

所以,你只需要摆脱胆怯的情绪,就可以很容易地去参与其中。例如1我们的大型分布式数据库DORIS,就给新手提供了非常友好的Good First Issues栏目,你可以非常容易地选择一个自己想要去完成的内容,然后接受导师的指导。

之后你会发现,原来参与一个开源项目并不是那么困难嘛~

作者网址:https://zclll.com/

d401a562584e1375bfe0bd61a124150b.png

整理不易,三连

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

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

相关文章

whatsapp的越狱特征检测

一、检测点 1、检测目录 opendir打开bin是否成功 2、检测模块 解析macho的header头获取加载的模块,获取进程的所有模块,判断是否包含如下模块:substrate,watusi,zdumper 3、检测文件 判定文件或是应用是否的路径是否存在 /Applications/Cydia…

单链表的相关操作(精简版..在修改中)

目录 前言: 哨兵位: 链表的概念 链表的相关操作: 链表的创建: 打印链表: 申请新节点: 链表的尾插: !!!对于传参中二级指针的解释: 链表的…

[C国演义] 第十六章

第十六章 等差数列的划分最长递增子序列 等差数列的划分 力扣链接 子数组 ⇒ dp[i]的含义: yinums[i] 为结尾的所有子数组中的 等差数列数组最多的个数子数组⇒ 状态转移方程: 根据最后一个元素的构成 初始化: 涉及到 i-1, i-2 ⇒ 所以要初始化dp[0] 和 dp[1] 都初始化为 0…

一次不成功的抓包过程

想搞Android app抓包,简单的方法,已经不起作用,打开charles代理工具,抓不到我的目标app任何请求,搞了两三天,也没成功。 我的目标APP里,经过apk反编译出来,看到有libflutter.so文件&…

AM@导数的应用@二阶导数的应用@函数的性态研究@函数图形的绘制

文章目录 概念称呼说明驻点极值和极值点最值极值点和最值比较曲线的凹凸性凹凸性判定定理👺例证明 凹凸性和单调性无必然关系拐点寻找拐点👺 函数图形的绘制例 概念 本文讨论导数的应用:利用导数研究函数的性态相关定理主要通过Lagrange中值定理进行推导…

首篇大模型压缩论文综述

首篇大模型压缩综述来啦!!! 来自中国科学院和人民大学的研究者们深入探讨了基于LLM的模型压缩研究进展并发表了该领域的首篇综述《A Survey on Model Compression for Large Language Models》。 Abstract 大型语言模型(LLMs&a…

文件操作 IO

文件(File) 狭义的文件: 指的是硬盘上的文件和目录 广义的文件: 泛指计算机中很多软硬件资源(操作系统中把很多硬件和软件资源抽象成了文件, 按照文件的方式同意管理) 本章内容只讨论狭义的文件 路径 绝对路径: 以c: , d: 盘符开头的路径相对路径: 以当前所在的目录为基准(…

【问题思考总结】如何求椭圆的切线?【过椭圆外一点】

问题 今天做2009年数一的真题,发现第17题求切线十分难顶,我用的方法是切线和椭圆方程联立,还有切线斜率和椭圆上一点和远点斜率相乘等于-1的方法。 思考 经过思考后,我认为之前的那个属于是高中方法(还不完全是&…

Prometheus接入AlterManager配置邮件告警(基于K8S环境部署)

文章目录 一、配置AlterManager告警发送至邮箱二、Prometheus接入AlterManager配置三、部署PrometheusAlterManager(放到一个Pod中)四、测试告警 注意:请基于 PrometheusGrafana监控K8S集群(基于K8S环境部署)文章之上做本次实验。 一、配置AlterManager告警发送至邮…

手把手入门Node框架Egg.js

0.介绍 Egg.js 是一个面向企业级应用开发的 Node.js 框架,它建立在 Koa.js 之上,提供了一种更简单、灵活的开发方式。Egg.js 提供了一些默认约定和最佳实践,可以帮助开发者快速构建可靠、可扩展的应用程序。 基于 Koa.js:Egg.js …

spacy.load(“en_core_web_trf“)报错TypeError: issubclass() arg 1 must be a class

使用spacy时遇到的问题 写在最前面: 安装spacy和en_core_web_trf时需要保证二者版本一致 安装及查看对应spacy版本 安装 pip install spacy查看版本 import spacy spacy.__version__安装en_core_web_trf 直接安装(如果可以的话) pytho…

【论文阅读】以及部署BEVFusion: A Simple and Robust LiDAR-Camera Fusion Framework

BEVFusion: A Simple and Robust LiDAR-Camera Fusion Framework BEVFusion:一个简单而强大的LiDAR-相机融合框架 NeurIPS 2022 多模态传感器融合意味着信息互补、稳定,是自动驾驶感知的重要一环,本文注重工业落地,实际应用 融…

反转链表review

反转链表 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode next) { this.val val; this.next next; }* }*/ class …

Rust逆向学习 (2)

文章目录 Guess a number0x01. Guess a number .part 1line 1loopline 3~7match 0x02. Reverse for enum0x03. Reverse for Tuple0x04. Guess a number .part 20x05. 总结 在上一篇文章中,我们比较完美地完成了第一次Rust ELF的逆向工作,但第一次编写的R…

JVM(Java Virtual Machine)垃圾收集器篇

前言 本文参考《深入理解Java虚拟机》一书,本文主要介绍几个经典的垃圾收集器:Serial、ParNew、parallelScavenge、CMS、Serial Old、Parallel Old、G1 本系列其他文章链接: JVM(Java Virtual Machine)内存模型篇 JV…

2434: 【区赛】[慈溪2013]统计方格

题目描述 给出一张 n 行 m 列仅由黑白方格组成的黑白图片(行从上到下 1 到 n 编号,列从左到右 1 到 m 编号)。如下图是一张由 17 行 18 列方格构成的黑白图片,图片中的任意一个方格要么是白色,要么是黑色。 仔细观察这…

介绍Sigmoid函数的平移、平滑和翻转【基于Python可视化分析】

文章目录 简介Sigmoid函数Sigmoid函数曲线调控参数设置python可视化参考 简介 本篇博客介绍了具有S型曲线的Sigmoid函数,以及如何设置、调整Sigmoid函数的参数实现S曲线的平滑、平移和翻转操作。博客给出了Python代码示例,更加深刻形象。😆&…

hdlbits系列verilog解答(两输入与门)-06

文章目录 wire线网类型介绍一、问题描述二、verilog源码三、仿真结果 wire线网类型介绍 wire线网类型是verilog的一种数据类型,它是一种单向的物理连线。它可以是输入也可以是输出,它与reg寄存器数据类型不同,它不能存储数据,只能…

数据结构与算法 | 第二章:线性表

本文参考网课为 数据结构与算法 1 第二章线性表,主讲人 张铭 、王腾蛟 、赵海燕 、宋国杰 、邹磊 、黄群。 本文使用IDE为 Clion,开发环境 C14。 更新:2023 / 10 / 22 数据结构与算法 | 第二章:线性表 线性表总览线性结构概念特…

大数据技术学习笔记(三)—— Hadoop 的运行模式

目录 1 本地模式2 伪分布式模式3 完全分布式模式3.1 准备3台客户机3.2 同步分发内容3.2.1 分发命令3.2.2 执行分发操作 3.3 集群配置3.3.1 集群部署规划3.3.2 配置文件说明3.3.3 修改配置文件3.3.4 分发配置信息 3.4 SSH无密登录配置3.4.1 配置ssh3.4.2 无密钥配置 3.5 单点启动…