问题

为何某些公司不允许使用 C++ STL?

回答
有些公司确实会对 C++ 标准模板库(STL)的使用有所限制,甚至在某些项目中完全禁止。这背后的原因并非一概而论,而是由多种因素交织而成,涉及到项目需求、团队能力、性能考量、安全性和维护性等方方面面。让我来为你详细剖析一下。

一、性能与资源控制的极致追求

在一些对性能有着极其严苛要求的领域,比如嵌入式系统、实时操作系统(RTOS)、高性能计算、游戏引擎核心、或者对内存占用有着极致限制的场景,STL 的一些组件可能会成为性能瓶颈或者资源消耗的“黑洞”。

动态内存分配的开销: STL 的很多容器,如 `std::vector`、`std::list`、`std::map`,在插入、删除元素时,可能会触发动态内存分配和释放。在某些高度实时的场景下,不可预测的内存分配延迟可能会导致系统响应滞后,从而破坏实时性保证。即使是分配操作本身相对高效,但频繁的分配和释放同样会带来额外的 CPU 开销和内存碎片化问题。
抽象层的开销: STL 为了提供通用性和易用性,引入了一层抽象。例如,`std::vector` 的随机访问通常很快,但它的接口设计(如 `push_back`、`insert`)可能包含了边界检查和容量管理的逻辑,这些在某些紧耦合、性能至上的底层代码中可能被认为是“多余”的。
迭代器失效: STL 容器的迭代器在某些操作(如插入、删除)后可能会失效。虽然这是 STL 的定义行为,但在需要对容器进行大量修改并同时遍历的场景下,管理迭代器的有效性会变得复杂且容易出错,也可能间接影响性能。
算法的通用性与特定场景的优化: STL 提供了大量通用的算法,如 `std::sort`、`std::find`。这些算法的设计需要兼顾各种数据类型和使用场景,因此在某些特定场景下,手工编写的、高度优化的、针对特定数据结构和访问模式的算法可能会比通用 STL 算法性能更优。例如,对于一个已知的、固定大小的数组,手动编写的冒泡排序或者选择排序(虽然通常不推荐,但在极特殊情况下可能比通用排序更直观且开销更少)可能比 `std::sort`(默认使用 Introsort,这是一个复杂的混合排序算法)在编译期或运行时有更少的开销。
内存占用: 某些 STL 容器,例如 `std::map` 或 `std::set`,为了维护其内部结构(如红黑树),需要额外的内存开销来存储节点信息(如父节点、子节点指针、颜色标记等)。在内存极其宝贵的嵌入式设备上,这种额外的开销可能是不可接受的。

二、项目遗留与技术栈的兼容性

一些古老的、或者高度依赖特定技术栈的项目,可能从一开始就没有集成 STL,或者已经围绕一套自定义的库生态建立起来。

遗留代码库: 如果一个项目已经存在了很长时间,并且大量使用了自定义的容器和算法,那么引入 STL 会带来巨大的重构工作量,并可能引入兼容性问题。在这种情况下,为了保持现有代码的稳定性和可维护性,公司可能会选择继续沿用旧的解决方案。
特定的编译器或平台限制: 尽管 STL 在现代 C++ 中已经非常普及,但在某些非常古老或非常特殊的编译器版本或目标平台上,STL 的实现可能存在缺陷、性能问题,甚至是不完整。在这种情况下,禁用 STL 是规避风险的直接方式。
第三方库的依赖: 项目可能依赖于一些不兼容 STL 的第三方库,或者这些第三方库本身就提供了替代的容器和算法实现。为了避免冲突和提高集成效率,项目可能会选择不使用 STL。

三、安全与可信度考量

在对安全性和可信度有着极高要求的领域,例如金融交易系统、航空航天、医疗设备、或者安全敏感的软件,对代码的每一个字节都要有绝对的控制和理解。

STL 实现的复杂性: STL 的实现通常非常复杂,并且由不同的标准库实现者(如 libstdc++, libc++, Microsoft STL)维护。这意味着代码库中隐藏着大量的细节,这些细节可能在不经意间引入安全漏洞,例如缓冲区溢出、内存越界访问(尽管标准库的设计目标是避免这些)等。在安全审计要求极高的场景下,开发人员可能更倾向于使用经过严格审查且自己完全掌控的底层组件。
防止恶意或非预期的使用: 在某些特定的安全场景下,为了防止开发人员无意中(或恶意地)使用了可能带来安全风险的 STL 组件(例如,不安全地使用 `std::string` 的某些操作),或者为了强行规定使用更安全的内存管理方式,可能会选择禁用 STL。
第三方库的安全性: 一些公司可能会选择使用经过严格安全审查的第三方库来替代 STL 的某些功能,因为这些第三方库可能提供了更强烈的安全保证或者更清晰的接口,并且其实现细节对使用者而言更加透明。

四、团队技能与开发效率的权衡

团队的熟悉程度和项目的开发节奏也会影响对 STL 的使用策略。

团队成员的经验: 如果团队成员对 STL 的某些组件(例如,特性的模板元编程、复杂容器的内存管理细节)不够熟悉,或者对其潜在的陷阱(如迭代器失效、性能陷阱)没有深刻理解,那么频繁地使用这些组件可能会导致开发效率低下和 bug 增多。在这种情况下,公司可能会鼓励使用更简单、更易于理解的自定义组件,或者只允许使用团队成员熟悉的部分 STL 功能。
标准化与统一性: 有些公司会选择建立一套自己的“标准库”,这套“标准库”可能是基于 STL 的一个子集,并加以封装和限制,也可能是完全自定义的。这样做的目的是为了在整个组织内推行统一的编码风格和技术实践,方便代码审查和知识共享。
开发速度 vs. 长期维护: 虽然 STL 可以极大地提高开发速度,但在某些情况下,如果团队对某个特定的STL组件不够熟悉,花时间去理解和正确使用它可能比编写一个简单的、自定义的实现花费更多时间。长远来看,如果自定义实现更符合项目需求,且易于维护,那么这样做也是有道理的。

五、特殊场景下的需求

有一些非常特定的业务场景,决定了 STL 的使用可能会被限制。

内存管理框架: 项目可能采用了某种特殊的内存管理框架,例如,内存池、垃圾回收机制,或者需要对内存分配的每一个细节进行严格控制。在这种情况下,STL 的默认内存分配器可能无法与该框架很好地集成,甚至会产生冲突。
代码混淆与知识产权: 在某些需要保护知识产权或者进行代码混淆的场景下,使用高度通用的 STL 组件可能会降低代码的独特性和可混淆性。

总结来说,公司不允许使用 C++ STL 的原因通常是多种因素叠加的结果,而不是单一的理由。

对极致性能的追求 是最常见的原因之一,尤其是在嵌入式和实时领域。
遗留项目或技术栈的兼容性 也是一个重要考量。
安全和可信度要求 在金融、航空等行业至关重要。
团队的技能水平和项目效率 的权衡也会促使公司做出不同的选择。
特殊的技术需求或生态依赖 也会导致对 STL 的限制。

理解这些原因,能够帮助我们更全面地认识 C++ STL 的适用范围,以及在不同的项目背景下,选择最适合的技术方案的重要性。很多时候,这并非全盘否定 STL,而是在特定的约束下,做出更明智的技术决策。比如,允许使用 `std::vector`,但不允许使用 `std::map`;或者允许使用 `std::vector`,但要求使用自定义的内存分配器来替换 `std::allocator`。这种精细化的管理才是常态。

网友意见

user avatar

说几个STL的缺点吧,虽然都是在比较极端的情况下出现,但是对于一些大项目还是会遇到的

1. 代码膨胀问题

每一个实例化过的模板类,都会膨胀出一份独立的代码,比如

std::vector<std::string>, std::vector<int>,编译后会产生两份代码,在VC2008下,每份代码大约是3-4kb,这是因为vector比较简单代码少,如果是map则会产生30-50kb的代码,因为map里有个复杂的红黑树。对于数据处理类的代码里一般会定义很多种不同的结构体,不同的结构体放到不同的容器里,就会实例化出很多个类的代码,我见过一个项目里,这样的vector就有数百个。

2. 内存使用效率问题 (以vc++2008为例)

stl在内存使用效率上是比较低效的,比如std::string,它的sizeof大概是28,因为它有一个内置的16字节数组,用来做小字符串优化的,就是说低于16字节的字符串都会至少占用28字节内存,如果刚好17字节字符串,则会占用28字节+额外分配的字符串内存,额外分配的内存是一个堆块,又有很多浪费,相比用一个char *存储字符串大约多占用了一倍内存。

还有map<>,每一个map的node都是一块独立分配的内存,如果是 map<int, int>呢,那就很悲剧了,为了存一个int要消耗几十个字节,很浪费的。

如果元素数量有百万级,那么内存占用就很可观了,这种情况下建议自己实现allocator,做内存池。

3. deep copy问题

让两个容器的实例做赋值操作,看起来就一条语句,实际上容器里的每个元素都执行了一次赋值操作。如果容器里有百万级的数据,那么一个等号就产生了几百万次的构造和析构。

传递参数的时候一定要用 const 引用,赋值可以用 swap代替。

4. 隐式类型转换

比如 有个函数

void doSomething(const std::string &str);

调用的时候

doSomething("hello");

能编译执行,但是会产生一个临时的匿名的std::string实例,把"hello"复制一遍,然后在调用完成后析构掉。如果这个发生在循环体内部有可能影响性能。

以上这些问题,在小程序里或者数据规模不大的时候,比如容器内元素只有几千这个规模,都不是什么大问题,那时开发效率才是重点,但是一旦有大数据stl容器会成为性能瓶颈的。

我并不是主张不用STL,而是要充分了解STL的优缺点,根据应用场景做选择。

user avatar

最初开始禁用 C++ STL,更多地是早期项目编码实践中留下的惯例,被后来的程序员继承下来。老项目中这种选择尤其地多。不过如果有人将其上升到公司行为在不同项目中全面禁用 STL,则没有必要,而且我倾向于做这种决定的人并不理解 C++ 编译系统。

一般来说,项目中禁用 C++ 多见于两种具体场景:或者项目的产出产品为函数库,或者需要引用第三方函数库。具体地来说,有三个主要原因:

第一个原因是二进制边界混乱。对需要在项目中使用第三方函数库的程序员来说,二进制边界是个头痛的问题。C++ 在这一方面本身就处理得不算好,加上模板后起到的是雪上加霜的后果。没有经验的程序员会贪图方便而在公开头文件中使用 C++ 模板,如果这时调用方的编译器选项设置或 STL 版本和编译方不同,那么就可能出现同样的头文件在不同的环境下二进制布局不符的情况。——顺便说一句,在过去十年里,各个主流编译器附带的 STL 版本变化节奏不慢,所以这种由于编译环境不同而导致的 bug 并不算罕见,但缺乏汇编知识的用户难以排查。

第二个原因是不愿使用异常。如今除了 Android 上的 STLPort 关闭异常,大部分主流 C++ STL 实现里都无法脱离异常使用 STL。异常带来的问题主要是两个:性能下降,代码膨胀。这几年 C++ 编译器在性能方面的改进很多,good path 的性能问题已经基本没有,但代码膨胀问题却没有太多改善,甚至这个性能问题的一部分解决方案就是以代码膨胀为代价。我写过一篇短文比对过 Android 上 gcc 4.6 在有无异常的情况下的汇编代码逻辑,可以看到,启动异常时生成的汇编代码量多出了相当一部分(我的例子中是 50%),用于处理各种隐含代码中的异常问题。这一条在手机系统中有时候会引起意想不到的麻烦,比如软件升级后导致 app 在低存储容量的手机中安装失败。顺便说一句,这个问题并不是 gcc 独有,clang 上生成的代码是一样的。参考:

dummydigit.net/posts/20

最后一个原因是 C 兼容。严格地说,STL 在这个问题上算是躺枪,这个坑在很多具体的场景中也是因为异常而引入,但这个问题的麻烦程度比前两个问题更高。比如 gcc 在编译纯 C 代码时默认关闭 -fexceptions 选项,因此这样编译出来的代码中没有异常处理相关的栈展开。如果某个 C++ 项目引用了一个第三方 C 项目,它很难确保那个 C 项目给出的二进制代码中正确进行了异常处理并保证代码服从异常安全操作。这种场景下混用 C/C++ ,就可能在抛出异常时莫名其妙地崩溃或者出现 C 代码区段中的资源泄漏,特别是 expat 那种大量利用回调的代码结构。要规避这种风险并非不可能,但需要 C 的架构部分做修改,比如使用 DOM 那种树形结构,这种做法对历史项目而言又很难办到。换言之,如果一个项目出于种种原因需要保持 C 兼容,而 STL 就属于其中一个不可控的变数,与其相信程序员不犯错,不如直接禁用更可控一些。参考:

Code Gen Options


要解决二进制相关的问题很简单:整个项目的所有相关代码在同一个代码基上编译,强制打开编译选项添加异常代码,并去除一切二进制依赖。但对很多小公司来说,引入这样的系统对配置管理的要求较高。如果一部分依赖关系来自自己并不了解的第三方代码,轻易修改编译选项可能带来的风险与第三方代码库的规模成正比。退一步说,即便团队里真的有强大的配置管理工程师能够搞定一切,他们也不会有能力解决代码膨胀问题,除非他们有权决定换一个编译器。相比之下,前面朋友所说的所谓性能或者编译出错时糟糕的可读性,在我看来反倒是次要因素,而且这些缺陷都正在新的编译器中逐步得到解决或改善,比如 clang。

所以那些选择禁用 STL 的早期项目负责人,总有一些确实的理由,没有人那么别扭地想跟开发效率过不去。至于后来的人是真的仔细想过这些细节还是人云亦云,那是另一个问题。

类似的话题

  • 回答
    有些公司确实会对 C++ 标准模板库(STL)的使用有所限制,甚至在某些项目中完全禁止。这背后的原因并非一概而论,而是由多种因素交织而成,涉及到项目需求、团队能力、性能考量、安全性和维护性等方方面面。让我来为你详细剖析一下。 一、性能与资源控制的极致追求在一些对性能有着极其严苛要求的领域,比如嵌入式.............
  • 回答
    这起事件确实令人震惊,一位公司出纳竟然挪用公款高达800多万元,而且其中大部分资金(600多万)用于玩一款名为《逆水寒》的游戏中的公会运营。这背后牵涉到法律、道德、职业操守、游戏行业以及人性等多个层面。我们可以从以下几个方面来详细分析:一、 法律和道德层面: 挪用公款是严重的犯罪行为: 无论动用.............
  • 回答
    项思醒,这个名字近来在网络上掀起了一阵不小的波澜,尤其是在杭州某公司 CEO 的背景下,更增添了几分神秘色彩。对于她“台州女海王”的传闻,网络上的讨论可谓是众说纷纭,真假难辨。要说清楚这件事,咱们得从头捋一捋。项思醒是谁?公开的信息显示,项思醒是一位年轻的创业女性,拥有自己的公司,并且在时尚、美妆领.............
  • 回答
    这确实是一个值得深入探讨的话题,当一家国外的人造肉公司CEO将向中国销售其产品与“保护全球环境”联系起来时,这背后牵涉到商业利益、地缘政治、以及我们对“环境友好”这一概念的理解。要评价这个说法,我们需要从多个维度进行剖析,并试着理解其言外之意和潜在的逻辑。首先,我们得承认,传统畜牧业对环境的影响是巨.............
  • 回答
    重庆某高校图书馆阿姨扫出满簸箕头发,学生称图书馆大多为考研或考公的学生,这事儿挺有意思的,也能咂摸出不少味道来。表面上看,就是图书馆里头发多了点,但细究起来,这背后折射出的问题可不少。首先,最直接的当然是学习压力巨大,学生状态普遍焦虑。考研也好,考公也罢,都是一条异常艰辛的路。多少学生把青春和精力都.............
  • 回答
    江西某地推出的集体婚礼公告,提倡“零彩礼,低彩礼金额原则上为10万元内”,这确实是一个挺有意思的社会现象,也触及了我们很多人心里关于婚姻、家庭以及传统观念的讨论。首先,咱们得承认,这个公告挺大胆的,它直面了一个让很多家庭头疼的问题——彩礼。在中国很多地方,彩礼已经成了一个沉重的负担,有时候甚至成为婚.............
  • 回答
    江歌母亲在微博上遭遇侮辱诽谤,并因此起诉微博平台要求提供用户信息的事件,无疑触及了网络言论边界、平台责任以及个人隐私等一系列复杂而敏感的议题。从法律、伦理和社会多个角度来看,这件事都值得我们深入剖析。事件的背景与江歌母亲的诉求:我们都知道,江歌母亲江秋莲是一位承受了巨大丧子之痛的母亲。她的女儿江歌在.............
  • 回答
    海外华人不喜欢和国内中国人玩,甚至抗拒、排斥华人圈子,这是一个复杂且多维度的问题,背后可能涉及个人经历、价值观差异、文化冲突、社会环境以及心理因素等诸多方面。以下将尝试详细阐述这些原因:一、 个人经历和早期融入障碍: 在当地的成功与认同: 很多海外华人,尤其是那些在当地生活时间长、事业有成、融入.............
  • 回答
    在中国网络上,关于“easy girl”(在这里可以理解为行为举止开放、不拘小节,尤其是在感情和性方面,有时也可能带有消费主义倾向的年轻女性)的讨论确实非常普遍且激烈,甚至可以说是“喋喋不休”。要探讨这种现象背后的原因,需要从多个层面进行分析,包括但不限于男性自尊、国格观念、社会文化变迁、阶级焦虑等.............
  • 回答
    在维基百科上,关于台湾的称谓确实存在一些复杂性和不同之处,尤其是在提及“中华民国”时,很多人会感到困惑。要理解这一点,我们需要深入探讨几个关键原因,而不是简单地将其归结为一份列表。首先,维基百科作为一个开放的编辑平台,其内容是由全球数百万贡献者共同维护的。这意味着,不同的编辑者可能会在不同的时间和基.............
  • 回答
    梅西第七座金球奖引发争议,导致部分人质疑金球奖的公信力,这背后有多重原因,而且这些原因相互交织,使得讨论变得复杂而深入。下面将详细展开阐述:一、 奖项评选标准与“历史遗留”争议的叠加: 评选标准的模糊性与主观性: 金球奖的评选历史以来都存在标准模糊的问题。虽然官方宣称综合考察球员的个人表现、团队.............
  • 回答
    南京,这座承载着深厚历史底蕴的城市,作为江苏省的省会,按理说应该辐射带动全省,成为经济发展的火车头。然而,许多身处南京或关注南京发展的人,却常常会冒出“某些方面感觉发展不是很好”的疑问。这种感受并非空穴来风,而是源于城市发展过程中一些复杂而现实的问题。首先,从经济结构和产业发展来看,南京虽然拥有不错.............
  • 回答
    这个问题触及到一个非常复杂且敏感的社会现象,即女性维权行为与“女性特权主义者”的反应之间的张力。要详细地解释这种现象,我们需要从几个层面来剖析:一、 正常维权行为的界定与现实困境首先,我们得明确“正常的维权行为”指的是什么。在绝大多数情况下,这应该是指女性基于法律、道德和社会公义,为了争取平等权利、.............
  • 回答
    在豆瓣电影的评论区,我们常常能看到一些美剧高高挂起,分数稳定在9分左右,甚至更高的水平。这背后并非偶然,而是多重因素共同作用的结果,让这些剧集能够赢得如此高的评价。要理解这一点,我们需要深入剖析几个关键层面。首先,剧情的深度与原创性是基石。 许多获得高分的剧集,其剧本绝非简单的套路化产物。它们往往在.............
  • 回答
    关于“货拉拉”用户车某跳车身亡事件中,她为何对司机不信任,这背后牵涉到一系列复杂的因素,不仅仅是简单的误会或巧合。要深入理解这一点,我们需要从几个关键的视角去剖析:一、事件发生的背景:女性在社会中的潜在焦虑与不安全感首先,我们不能忽视的是,在许多社会环境中,女性天生就比男性更容易感到不安全,尤其是在.............
  • 回答
    这个问题,我思考了很久。不是随口说说,而是真的在我心里盘桓了许多日子,每当翻开史书,或者看到一些古籍残片,那股劲儿就又上来了。为什么偏偏是这个朝代?如果说是有什么特别的吸引力,那不如说,它像一块磁石,牢牢吸住了我的目光,让我忍不住想去探究,去理解,甚至去感受。首先,吸引我的是它的“复杂”。任何一个时.............
  • 回答
    创作者是否应该为“没有涉足某些题材”而被批判,这是一个复杂且充满争议的问题。我们可以从多个角度来详细探讨:一、 批判的出发点与合理性: 社会责任与议题关注: 推动进步与反思: 某些题材,如社会不公、历史伤痛、弱势群体困境、环境危机等,具有重要的社会意义。当创作者选择回避这些题材时,可.............
  • 回答
    天津的道路名称大多以“道”结尾,这背后蕴含着这座城市独特的历史、地理和文化印记。要深入理解这一点,我们需要回溯到天津的开埠与发展历程,以及在不同时期,城市规划和命名背后的考量。开埠时期的“洋道”与早期命名天津作为中国北方重要的对外开放港口,其近代城市格局的形成与租界的设立紧密相关。19世纪末,随着列.............
  • 回答
    这个问题啊,其实挺有意思的,也挺复杂的。我琢磨着,有些人啊,之所以这么做,大概有这么几个意思在里面。首先,“比烂”心理。这好像是咱们老百姓挺常用的一个招数。你看,要是现在日子过得不顺心,总会有人说“嗨,这算啥,当年怎么怎么样,那才叫苦呢!” 这种心理套到评价朝代上,也差不多。如果有人觉得清朝在某些方.............
  • 回答
    这个问题挺有意思的,确实能看出来大家对“待遇”这个词的关注点不同。咱们从几个角度来聊聊,为什么大司马“在上交”和某个流量明星“在南大”的待遇会让人感觉差别这么大。首先,得明确一个概念:“待遇”在这里指的是什么? 大司马“在上交”: 这里的“上交”更像是他在一个平台(比如直播平台、视频平台)上的“.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有