【问题标题】:Drawbacks to templates and the STL in C++ [closed]C++ 中模板和 STL 的缺点 [关闭]
【发布时间】:2010-09-20 23:01:15
【问题描述】:

使用 STL 或模板有什么缺点吗?是否有不适合的情况。

【问题讨论】:

    标签: c++ templates stl


    【解决方案1】:

    首先,如果它们可以帮助您解决问题,您应该使用可能使用它们。模板是 C++ 中非常重要的一部分,并且多年来一直是标准的一部分。 STL 在运行时非常强大且速度很快,应该得到所有体面的编译器的支持,但当然也存在一些问题。

    • 如果您有一个非常旧的编译器,则可能不完全支持 STL。
    • STL 实现的线程安全性可能适用于您的应用程序
    • 模板可能会导致编译时间变慢并可能导致更大的可执行文件,尤其是使用较旧的编译器。
    • 编译器经常在使用模板的代码上产生难以理解的错误消息。

    仅举几例,但不使用它们的缺点可能要大得多。

    【讨论】:

    • 您认为模板的错误信息很糟糕,请尝试去掉类头文件末尾的分号! ;)
    • STLfilt 对错误消息有很大帮助。
    • 与尝试在多线程应用程序中查找同步错误相比,这两者都不算什么;)
    • @Luc:感谢 STLfilt 的建议。我不知道这件事。我刚试了一下,看起来还不错。
    【解决方案2】:

    明显的缺点:

    • 语法可能很糟糕 - C++ 中的一些模板语法确实突破了理智的极限,并与语言的其他部分重叠(例如 >>)

    • 很多人不太了解 STL,因此您可能会限制您的受众。

    • 错误消息往往非常复杂。

    • STL 集合的设计往往会导致大量的对象复制。最初的“智能指针”(std::auto_ptr)不适合在大多数集合中使用。最近这方面的情况有所改善(TR1)

    【讨论】:

    • C++0x 应该有助于改进其中的一些。 “>>”的东西是要修复的,概念应该有助于产生更好的错误消息。
    • 更不用说移动语义确保对象的复制变得相当有效。
    【解决方案3】:

    有几个潜在的好处和缺点

    • 模板会扩大生成代码的大小。
    • 在编译时扩展和处理模板代码,这可能会延长编译时间。 (另一方面,可执行代码可能更高效)。
    • 误用 STL 元素会导致代码变慢
    • STL 实际上使代码更具可读性(我的观点与 Will 不同)。与任何语言或库一样,您必须了解它才能适当地使用它……这对于了解它的人来说是一个缺点。
    • 如果您在元编程意义上使用模板(不要与使用 STL 混淆),代码看起来像是一种与 C++ 完全不同的语言。解析代码实际在做什么可能更难。 (OTOH,做得对 - 元编程让您专注于架构和设计;它还为编译时间和运行时带来更多错误。当您拥有关键功能并且您可以捕获错误编码的部分时,这是一个巨大的胜利在编译时而不是让客户在运行期间捕获它!)

    话虽如此,我们使用 C++ 和模板(在某些领域还使用元编程技术)来为我们的整体代码库带来好处。代码比没有模板时的代码略大,但性能和可维护性的权衡大于大小。我们确实有熟练/经验丰富的 C++ 程序员致力于开发和维护代码。

    如果您使用缺点来决定是否使用 C++ 功能/库 - 请确保您同样权衡语言的好处以及您的项目/产品/公司愿意权衡的好处。希望这会有所帮助。

    编辑:我忘记提及的另一个主要缺点 - 便携性。如果您需要编写可移植的代码,模板可能不是正确的方法。当今大多数流行的编译器都支持 STL,但大多数并不是全部。元编程技术可能是可移植性的真正杀手,因此这是决定其使用适当性的明确考虑因素。

    【讨论】:

      【解决方案4】:

      用于嵌入式设备编程(在我的例子中——智能手机)。由于担心生成的代码大小(少量 RAM 和磁盘空间),不鼓励使用模板。此外,编译器非常古老,可能无法处理一些与模板相关的构造。

      【讨论】:

        【解决方案5】:
        1. 大量模板滥用(尤其是 模板元编程和Boost 成瘾)会导致过度 编译和链接时间长。

        2. 您还可以使用可执行文件 有相当大的 (未剥离的)二进制文件,但通常 这不是一个可怕的问题。

        3. 设计不佳的模板也可以 进一步增加代码重复 加剧可执行文件大小 问题。

        4. 对于具有大 实现还需要 考虑这样一个事实,即使用 他们的模板意味着移动 整个类体变成一个标题 某处。这地方多了很多 如果模板加载链接器 在多个地方使用。

        5. 来自大量模板化代码的错误消息可能会让外行人望而生畏,而且很少能像从非模板化代码中得到的错误消息那样清晰。

        也就是说,对于大多数应用程序来说,模板是代码重用的绝佳工具,有助于提升从重新实现到重用代码的讨论水平;这些问题很少能胜过好处。

        【讨论】:

          【解决方案6】:

          套用现代 C++ 设计名声的 Andrei Alexandrescu 的话。 Template are an orthogonal structure to multiple inheritance。它们都有互补的权衡和好处。模板具有丰富的机制,但模板的专业化无法扩展。

          【讨论】:

            【解决方案7】:

            模板的目标是以最小的性能损失提供抽象。在大多数情况下,利大于弊。模板的大部分问题来自编译器和调试器的支持。

            我对模板的不满:由于标头依赖性,它击败了智能构建系统。与开发纯面向对象的系统相比,开发模板代码往往会导致更多的未修改代码的重新编译,尤其是如果后者很好地使用了 DIP(依赖倒置原则)。这加剧了慢编译问题。 OTOH,如今更快的开发硬件使事情比以前更容易忍受。

            对于 STL(以及 Boost),他们的目标是提供可移植且合理高效的数据结构和算法。对于某些性能关键的应用程序,它们不一定是最佳选择。例如:虽然hash_map (tr1/unordered_map) 在一般情况下表现得相当好,但特殊用途的哈希表(例如,google 稀疏/密集哈希表库)在内存使用或速度方面可以大大优于通用 STL 实现。

            【讨论】:

              【解决方案8】:

              有很多支持和反对 C++ 模板的哲学(充其量)论据,但我倾向于接受最多的一个是在编译时实例化它们的机制会产生大量的代码膨胀。

              虽然这通常不是什么大问题,但当您为二进制大小限制非常有限的嵌入式系统编写代码时,它会产生重大影响。

              【讨论】:

              • “代码膨胀”对于支持模板的早期编译器来说是一个真正的问题,但现在不是。
              【解决方案9】:

              在 MSVC 实现中,std::string 每个字符串有 26 个字节的开销,即使字符串为空。如果您只使用 char*,则每个字符串将是 4 个字节。

              【讨论】:

              • 是的,这可能是他们所做的“小字符串”优化,基本上如果字符串足够短,他们将使用字符串对象内部的缓冲区,而不是从堆中分配一个。
              • 不一定是坏事。小字符串优化会对性能产生巨大影响,因为它大大减少了内存分配的数量。因此,我的一个程序使用 MSVC 比 gcc 快得多。 ——
              【解决方案10】:

              复杂的 STL 容器(以及任何复杂的 C++ 类)使调试变得更加困难。

              除了前面提到的不可读的错误消息之外,当前的调试器通常很少支持处理 STL 结构。例如,在运行时检查原生 C 数组比 vector 容器容易得多。

              希望情况会随着时间而改变。 除此之外,模板很棒。

              【讨论】:

                【解决方案11】:

                其中一个原因可能是它们很难翻译成其他不支持模板的面向对象语言,例如 C# 和 Java,因此如果您有来自这些语言的开发人员组,他们将面临更陡峭的学习曲线。

                【讨论】:

                  【解决方案12】:

                  模板实例化的方式要求您在跨翻译单元共享模板时注意如何声明和定义模板。 “C++ 模板:完整指南”一书是有关如何处理此问题的良好信息来源。

                  模板的编译器和链接器错误消息往往非常非常冗长。你必须习惯这一点,我认为有一些脚本/工具可以让它们更具可读性,但我对它们没有任何经验。

                  但除此之外,模板也很棒!

                  【讨论】:

                  • 我觉得您将模板与宏进行比较很冒犯。
                  • 模板不在宏和编译代码之间。模板编译的代码。它们不像宏那样颠覆 C++ 类型系统,它们是由编译器编译的第一类构造——而不是由预处理器编译。
                  • 我同意,模板是编译后的代码,我同意,模板是宏所不是的一切。我(诚然措辞不当)的观点是模板实例化增加了组织代码的复杂性。我认为顺便说一句,这本书对代码、宏和模板有类似的陈述。
                  • 我引用“C++ 模板”(第 6 章):“模板与普通代码有点不同。在某些方面,模板介于宏和普通(非模板)声明之间。”
                  【解决方案13】:

                  请参阅 C++ FQA [原文如此] 中的 templates section,了解不使用模板的许多充分理由。

                  【讨论】:

                  • FQA 中充满了 FUD,应该这样对待。
                  猜你喜欢
                  • 2010-10-11
                  • 2011-05-06
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-05-06
                  • 1970-01-01
                  • 2013-09-07
                  • 1970-01-01
                  相关资源
                  最近更新 更多