一部纪录片,四十年 C++:从贝尔实验室的"带类的 C"到全球增长最快的主流语言

2026-06-05 18 预计阅读时间:1 分钟
来源:oschina.net AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:8 分钟

2026年6月4日,C++标准委员会前主席、现Citadel Securities技术Fellow Herb Sutter在个人博客宣布:《C++: The Documentary》正式在YouTube上线首播。近70分钟的影片,把C++从1983年AT&T贝尔实验室里那个叫"C with Classes"的实验项目,一路讲到今天成为全球四大主流编程语言中增长最快的那个。对任何一个写过C++的人来说,这部片子不只是怀旧——它解释了这门语言为什么能在四十年的骂声中越活越硬。

"C with Classes"的起点

1983年,Bjarne Stroustrup在贝尔实验室开始把Simula的类机制嫁接到C上。当时的想法很朴素:C能跑得快、能贴近硬件,但组织大规模代码时太原始;Simula有类、有继承,但运行时开销让人无法接受。把两者拼起来,就是"C with Classes"。

纪录片还原了那段时期的关键决策:Stroustrup坚持"零开销抽象"原则——你用类写代码,编译器应该生成和手写C差不多效率的机器码。这个原则后来成了C++整个设计哲学的底座,也是它和后来所有"更优雅"语言分道扬镳的根本原因。

三十年骂声中的进化

C++的历史几乎是一部"被嫌弃但不停生长"的历史。1998年C++98标准化时,模板已经引入,但语法晦涩、编译器实现参差不齐,社区怨声载道。2011年C++11出来,人称"新C++"——auto、范围for、智能指针、lambda、移动语义一口气塞进来,代码面貌彻底变了。此后C++14、C++17、C++20以三年一版的节奏推进,std::optionalstd::variant、概念(Concepts)、模块(Modules)、协程(Coroutines)逐个落地。

纪录片里有一组数据特别醒目:C++现在是全球四大主流语言(C、C++、Java、Python)中增长最快的。这听起来反直觉——毕竟社交媒体上"C++已死"的论调从未断过。但数字不撒谎:高频交易、游戏引擎、嵌入式、操作系统内核、AI推理框架……这些对延迟和吞吐有硬性要求的领域,C++仍然是第一选择。增长的不是"写C++的人变多了",而是"必须写C++的场景变多了"。

四十年进化,代码长什么样

纪录片讲的是历史,但历史最直观的证据是代码本身。下面用一个最小例子,展示同一个"过滤+变换+输出"任务,在C++不同年代会怎么写。你可以直接编译运行——只需一个支持C++20的编译器(GCC 10+、Clang 10+、MSVC 19.28+)。

// evolution.cpp — 同一个任务,三种年代的写法
// 编译: g++ -std=c++20 -O2 evolution.cpp -o evolution

#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges>
#include <string>

struct Person {
    std::string name;
    int age;
};

// ── 1998年风格:手写循环 + 谓词函数对象 ──
void print_adults_c98(const std::vector<Person>& people) {
    struct IsAdult {
        bool operator()(const Person& p) const { return p.age >= 18; }
    };
    struct GetName {
        std::string operator()(const Person& p) const { return p.name; }
    };

    std::vector<Person> adults;
    std::copy_if(people.begin(), people.end(), std::back_inserter(adults), IsAdult());

    std::vector<std::string> names;
    std::transform(adults.begin(), adults.end(), std::back_inserter(names), GetName());

    for (std::vector<std::string>::const_iterator it = names.begin();
         it != names.end(); ++it) {
        std::cout << *it << "\n";
    }
}

// ── 2011年风格:lambda + auto + 范围for ──
void print_adults_c11(const std::vector<Person>& people) {
    std::vector<std::string> names;
    std::for_each(people.begin(), people.end(), [&](const Person& p) {
        if (p.age >= 18) names.push_back(p.name);
    });
    for (const auto& name : names) {
        std::cout << name << "\n";
    }
}

// ── 2020年风格:Ranges + 管道组合 ──
void print_adults_c20(const std::vector<Person>& people) {
    for (const auto& name : people
             | std::views::filter([](const Person& p) { return p.age >= 18; })
             | std::views::transform([](const Person& p) { return p.name; })) {
        std::cout << name << "\n";
    }
}

int main() {
    std::vector<Person> team = {
        {"Alice", 30}, {"Bob", 16}, {"Carol", 22}, {"Dave", 14}, {"Eve", 45}
    };

    std::cout << "=== C++98 style ===\n";  print_adults_c98(team);
    std::cout << "=== C++11 style ===\n";  print_adults_c11(team);
    std::cout << "=== C++20 style ===\n";  print_adults_c20(team);
}

运行结果三段完全一致,但代码量从98风格的约20行有效逻辑,缩减到20风格的3行管道表达式。这就是纪录片里反复强调的主题:C++没有抛弃性能,但它在持续压缩"写出正确高性能代码"所需的仪式性开销。

纪录片之外的实践启发

看完纪录片,几件事值得在日常工作里留意:

编译器版本不是小事。 C++20的Ranges、Concepts、Coroutines不是纸面标准——它们能不能用,取决于你团队用的编译器版本。如果还在GCC 7或MSVC 19.1x上,很多"新C++"你只能看着。升级编译器是采用新特性的第一道门槛,纪录片里几位标准委员会成员也承认,实现滞后是C++最大的痛点之一。

零开销抽象仍然是真的。 纪录片用高频交易和游戏引擎做案例——这些场景下,一微秒的额外开销就是钱或帧率的损失。C++的std::sortstd::views::filter、内联lambda,编译后和手写C循环的性能差距在大多数情况下可以忽略。但前提是你得用对:std::views是惰性视图,不分配内存;如果你顺手copy到一个新vectorsort,开销就回来了。

别在老项目里强行"现代化"。 纪录片提到C++98时代的代码库仍在运行——AT&T的电话系统、某些航天控制软件。这些代码不会因为C++20出了就重写。实际做法是:新模块用新特性写,老模块在维护时逐步替换危险模式(裸指针→智能指针,手写锁→std::scoped_lock),但不要为了"现代感"做大规模无业务驱动的重构。


近70分钟的纪录片,本质上是在回答一个问题:一门被吐槽了四十年的语言,为什么还在增长?答案藏在每一版标准的取舍里——C++从不追求"最优雅",它追求"在约束条件下最有效"。如果你还没看,YouTube上搜"C++: The Documentary"即可;如果你已经写了十年C++,这部片子会让你重新审视自己每天敲的那些templateauto背后,到底站着一个怎样的设计哲学。


相关推荐