【问题标题】:Good Idea / Bad Idea Should I Reimplement Most Of C++? [closed]好主意/坏主意 我应该重新实现大部分 C++ 吗? [关闭]
【发布时间】:2010-10-12 21:15:36
【问题描述】:

最近,在阅读了this 的博文后,我的脑海中出现了一个危险的想法。这个想法可以这样表达:

我不需要 C++ 标准库提供的大部分内容。那么,我为什么不实现一个不太通用但更易于使用的版本呢?

例如,使用 STL 会产生大量难以理解的编译器错误。但是,我不关心分配器、迭代器等。那么我为什么不花几个小时来实现一个易于使用的链表类呢?

我想从 StackOverflow 社区了解的是:对于 C++ 中的大多数现有功能,“自行开发”有哪些危险、可能的缺点和可能的优点?

编辑:我觉得人们误解了我的这个想法。我的想法是了解我是否可以实现一个非常小的 STL 功能集,大大简化了 - 更多的是作为一个项目来教我数据结构等。我不建议从头开始重新发明整个轮子,只是我需要和想要了解的部分。 我想我想弄清楚的是,使用 STL 的复杂性是否需要创建更小、更简单的版本。

重复使用 boost 或类似方法。

我编写的大部分代码都是为大学编写的,我们不允许使用外部库。所以要么是 C++ 标准库,要么是我自己的类。

这个问题的客观性。

这个问题不是主观的。它也不应该是社区 Wiki,因为它不是民意调查。我想要具体的论据来突出我的方法可能可能出现的一个优点或一个缺点。与流行的看法相反,这不是意见,而是基于经验或良好的逻辑论证。

格式。

请每个答案只发布一个缺点一个优点。这将允许人们评估单个想法,而不是一次评估您的所有想法。

请...

没有宗教战争。我不是任何语言的粉丝。我使用任何适用的。对于图形和数据压缩(我目前正在做的工作),这似乎是 C++。请限制您对该问题的回答,否则他们将被否决。

【问题讨论】:

  • 如果你这么不喜欢 C++,请放下骄傲,使用 STL 来完成你的任务,然后永远不要回到 C++。解决您的问题并为您节省大量时间。
  • 天啊。否决票是怎么回事?为什么人们不再陈述他们的理由?我只是不明白为什么这是一个糟糕的问题。
  • 我认为您将 C++ 与 STL 混淆了。前者是一种语言,后者——尽管是标准的一部分——只是一个提供的库,因此您不必从头开始编写所有内容。
  • 您声明您的问题不是主观的,但您自己使用了一些主观的术语和短语(例如,您开始说您不喜欢 C++,这是一个非常主观的短语!)。这引起了主观的回答。请改写或使问题主观。
  • 是时候提出另一个好主意/坏主意了。好主意:编写自己的 C++ 编译器。坏主意:用 COBOL 编写自己的 C++ 编译器。

标签: c++ code-reuse standard-library


【解决方案1】:

缺点:与解决摆在你面前的任何大学任务相比,你可能会花费更多的时间来调试你的类库。

优势:你可能会学到很多东西!

【讨论】:

  • 很好的答案,但你能把它分成两个答案吗?
【解决方案2】:

对于 C++ 中的大多数现有功能,“自行开发”有哪些危险、可能的缺点和可能的优点?

您能否负担得起并可能证明在重新发明轮子后花费的精力/时间/金钱是合理的?

重复使用 boost 或类似的。

很奇怪你不能使用 Boost。 IIRC,大部分贡献来自与大学相关/在大学工作的人(想想 Jakko Jarvi)。使用 Boost 的好处太多了,这里就不一一列举了。

关于不“重新发明轮子”

缺点:虽然你学到了很多东西,但当你想到你真正的项目目标是什么时,你也会让自己倒退。

优点:对于要继承它的人来说,维护更容易。

【讨论】:

  • 别问我...我的大学教授感染了“自己动手”综合症。这可能是一个好主意,也可能不是一个好主意!
  • 重新发明轮子时如何更容易维护?这难道不是意味着需要维护更多的代码,而熟悉它的人会更少吗?
  • 学校应该有“自己动手”综合症;做事就是你学习的方式。
  • @jalf:这“不是”重新发明轮子,请检查 ;-)
  • @Giovanni Galbo:如果我从实现 以使用 printf 开始,我就不会学到很多 C 语言。将其扩展到更大的比例。
【解决方案3】:

优点:吃自己的狗粮。你得到的正是你所做的。

缺点:吃自己的狗粮。许多人(比我们 99% 的人都聪明)花费数年时间创建 STL。

【讨论】:

  • 很好的答案,但你能把它分成两个答案吗?
  • 我有幸参加了一些标准委员会会议。我会通过一次修改来支持这种情绪,百分比可能更接近 99.99%!!!那里有一些非常非常聪明的人。
【解决方案4】:

缺点:恕我直言,重新实现经过测试和验证的库是一个漏洞,几乎可以保证麻烦大于其价值。

【讨论】:

    【解决方案5】:

    缺点:没有人会使用它。

    优势:在实现它的过程中,您将了解为什么标准库是一件好事。

    【讨论】:

    • 我认为这个优势很多。我实际上认为这可能值得整个 excersize!
    • 你能把这分成两个答案吗?
    • 是的,只有当你独自一人,泪流满面地站在海岸线上,看着好船 STL 将你的同学驶向项目交付之岛时,你才会意识到这一点。 . .而你自己在造船方面的可怜活动就在泻湖的底部。不要这样做芽
    • 担心 - 你假设这是为了一个项目,而不是为了学习。为了学习,这可能是最具教育意义的方法。这也是最耗时的。
    【解决方案6】:

    我建议你了解原因:

    使用 STL 会产生大量 难以理解和损坏的编译器 错误

    第一

    【讨论】:

    • 我只想能够阅读编译器消息!我真的不想知道为什么它们不可读。
    • 试试这个将 STL 编译器警告转换为人类可读形式的脚本:bdsoft.com/tools/stlfilt.html
    • 嘿,谢谢!这将是一个巨大的帮助!我希望我可以升级 cmets :)
    • 或者开始用编辑器减少东西。我看到的消息通常因为措辞过于复杂。
    【解决方案7】:

    缺点:你的大学课程可能是这样布置的。您对此感到非常恼火(无意讽刺)这一事实可能表明您没有得到范式,并且当您进行范式转变时会受益很多。

    【讨论】:

    • 我不确定我是否理解。 “你的大学课程可能是这样布置的”是什么意思?
    • @fluffels-我假设在设计您的课程时,为了涵盖特定的培训(?)目标,有些想法会涉及到哪些内容。因此,STL 可能是为了实现一个目标……可能只是为了让您了解编程中最流行的库之一。
    • 嗯...这是一门荣誉级别的课程。我怀疑那是他们的目标。我认为这只是一个不幸的副作用。
    • @fluffels-是的,我没看到
    【解决方案8】:

    优势

    如果您研究 MFC,您会发现您的建议已经在生产代码中使用 - 并且已经使用了很长时间。 MFC 的集合类都没有使用 STL。

    【讨论】:

    • 谢谢!最后,一个救赎的答案:) 你能不能给这个答案增加一个优势或其他东西?
    • MFC 的集合类中没有一个使用 C++ 标准库这一事实可能与 STL 的广泛采用和 MS 编译器完全编译它的能力都早于它有关。跨度>
    • 你肯定有道理。这很可能是原因。不过,也许他们只是不喜欢 STL 的命名约定、它的容器在调试器的监视窗口中的外观或它们的分配模式......
    • MFC 是出于不同的原因而设计的,它使用自己的集合类是因为它需要一些东西,而 STL 直到六年后才标准化。 MFC 最好使用标准容器等,但这将是一个令人难以置信的兼容性问题。
    【解决方案9】:

    为什么不看看现有的 C++ 库。在 C++ 还没有那么成熟的时候,人们经常编写自己的库。看看 Symbian(虽然很糟糕),Qt 和 WxWidgets(如果我没记错的话)有基本的集合和东西,可能还有很多其他的。

    我的观点是,STL 的复杂性源于 C++ 语言的复杂性,您几乎无法改进 STL(除了使用更合理的命名约定)。如果可以的话,我建议直接切换到其他语言,或者只是处理它。

    【讨论】:

      【解决方案10】:

      另一个缺点

      如果您想在大学毕业后获得一份 C++ 工作,大多数想要招聘您的人都会希望您熟悉标准 C++ 库。不一定对实现级别非常熟悉,但肯定熟悉它的用法和习语。如果您以自己的库的形式重新实现轮子,您将错过这个机会。尽管如此,如果你自己动手,你有望学到很多关于图书馆设计的知识,这可能会根据你面试的地点为你赢得一些额外的布朗尼积分。

      【讨论】:

      • 不,没有理智的雇主会期望应届毕业生彻底了解一门语言及其库。学位是为了学习原则。你在工作中学习图书馆。
      • 我(部分)不同意。如果我得到一个刚从大学毕业的人的简历,上面写着他们做过 C++ 编程,我希望至少对核心语言库有基本的了解。不是由内而外,是理所当然的。
      【解决方案11】:

      对于神秘的编译器 STL 错误消息,您可以采取一些措施。 STLFilt 将有助于简化它们。来自STLFilt Website

      STLFilt 简化和/或重新格式化 冗长的 C++ 错误和警告 消息,重点是 STL 相关的 诊断(对于 MSVC 6,它完全 消除 C4786 警告及其 碎屑)。结果呈现了许多 即使是最神秘的诊断 可以理解。

      看看here,如果您使用的是VisualC,还可以看看here

      【讨论】:

        【解决方案12】:

        缺点:重新实现所有很好(也就是说,以高质量的水平)肯定需要许多优秀的开发人员几年。

        【讨论】:

          【解决方案13】:

          那么,我为什么不实现一个 less 通用,但更易于使用的版本?

          因为你不能。因为无论你对 C++ 说什么,它都不是一门简单的语言,如果你还不是很擅长它,那么你的链表实现就会有问题。

          老实说,您的选择很简单:

          学习 C++,或者不要使用它。是的,C++ 通常用于图形,但 Java 也有 OpenGL 库。 C#、Python 和几乎所有其他语言也是如此。或者 C。你不必使用 C++。

          但如果你确实使用它,请学习并正确使用它。

          如果您想要不可变的字符串,请将字符串创建为 const。

          无论其底层实现如何,STL 都非常易于使用。

          C++ 编译器错误可以阅读,但需要一些练习。但更重要的是,它们并不是 STL 代码独有的。无论您做什么,无论您使用哪些库,您都会遇到它们。所以习惯他们。如果你习惯了它们,你也可以使用 STL。

          除此之外,还有一些其他的缺点:

          • 没有其他人会理解您的代码。如果您在 SO 上询问有关 std::vector 或双向迭代器的问题,那么熟悉 c++ 的每个人都可以回答。如果您询问 My::CustomLinkedList,没有人可以帮助您。这是不幸的,因为滚动你自己也意味着会有更多的错误需要寻求帮助。
          • 您正在尝试治愈症状,而不是原因。问题是你不懂C++。 STL 只是其中的一个症状。避免 STL 不会神奇地让您的 C++ 代码更好地工作。
          • 编译器错误。是的,它们读起来很讨厌,但它们就在那里。 STL 中的大量工作已用于确保在大多数情况下错误使用会触发编译器错误。在 C++ 中,很容易编写可以编译但不起作用的代码。或者似乎有效。或者在我的电脑上工作,但在其他地方神秘地失败了。您自己的链表几乎肯定会将更多错误转移到运行时,它们会在一段时间内未被发现,并且更难追踪。
          • 再一次,它会是越野车。相信我。我见过该死的优秀 C++ 程序员在 C++ 中编写一个链表,只是为了在隐蔽的边界情况下发现一个又一个的错误。而 C++ 都是边界情况。您的链表会正确处理异常安全吗?如果创建新节点(并因此调用对象类型的构造函数)引发异常,它会保证一切都处于一致状态吗?它不会泄漏内存,会调用所有适当的析构函数吗?它会是类型安全的吗?它会像以前一样高效吗?用 C++ 编写容器类时,有很多令人头疼的问题需要处理。
          • 您错过了以任何语言编写的现有最强大、最灵活的库之一。即使使用 Java 庞大的类库,STL 也可以做很多令人痛苦的事情。 C++ 已经够难了,没有必要放弃它提供的一些优势。

          我不关心分配器, 迭代器之类的

          可以安全地忽略分配器。你几乎不需要知道它们的存在。迭代器虽然很棒,但弄清楚它们会为您省去很多麻烦。要有效地使用 STL,您只需要了解三个概念:

          • Containers:你已经知道这些了。向量、链表、映射、集合、队列等。
          • 迭代器:允许您导航容器(或容器的子集,或任何其他值序列,在内存中,以流的形式在磁盘上,或动态计算)的抽象。
          • 算法:适用于任何对迭代器的常用算法。您有 sort、for_each、find、copy 等等。

          是的,与 Java 的库相比,STL 很小,但是当您结合上述 3 个概念时,它的强大功能令人惊讶。有一点学习曲线,因为它是一个不寻常的库。但是,如果您要花一两天以上的时间使用 C++,那么值得好好学习。

          不,我没有遵循您的答案格式,因为我认为实际上给您一个详细的答案会更有帮助。 ;)

          编辑:

          很有可能会说滚动自己的优势是您可以学习更多的语言,甚至可能为什么 STL 是它的可取之处之一。但我不太相信它是真的。它可能有效,但也可能适得其反。

          正如我上面所说,编写似乎可以工作的 C++ 代码很容易。当它停止工作时,很容易重新安排一些事情,比如变量的声明顺序,或者在类中插入一些填充,以使其看似再次工作。你会从中学到什么?那会教你如何编写更好的 C++ 吗?可能。但最有可能的是,它只会告诉你“C++ 很烂”。它会教你如何使用 STL 吗?当然不。 一种更有用的方法可能是利用 StackOverflow 的强大功能以正确的方式学习 STL。 :)

          【讨论】:

          • +1:我可以使用我的每日投票分配的少数答案之一,但不幸的是只能+1一次。一个真正优秀的答案,正确的答案,实际上是海报问题的唯一答案。干得好伙计。
          • 优秀的答案。使这被接受。你提出了一些非常好的观点。请放心,我确实“了解 C++”(与任何人一样多),只是我有时会感叹它过于复杂。
          • C++ 很复杂,但该库尽其所能使其易于使用。你或我不可能做得更好。
          • 有史以来最好的答案!无论如何我读过的最好的一个:-)
          【解决方案14】:

          STL 非常复杂,因为它需要用于通用库。

          STL 是这样的原因:

          • 基于交互器,因此标准算法只需要针对不同类型的容器进行单一实现。
          • 设计用于在遇到异常时正常运行。
          • 专为多线程应用程序中的“线程”安全而设计。

          然而,在很多应用程序中,您确实有足够的以下条件:

          • 字符串类
          • O(1) 查找的哈希表
          • 带有排序 / 的向量/数组和对已排序集合的二进制搜索

          如果你知道:

          • 您的课程不会在构造或作业上抛出异常。
          • 您的代码是单线程的。
          • 您不会使用更复杂的 STL 算法。

          然后您可能可以编写自己的更快的代码,使用更少的内存并产生更简单的编译/运行时错误。

          一些没有 STL 的更快/更容易的示例:

          • Copy-on-Write 字符串与引用计数字符串缓冲区。 (不要在多线程环境中执行此操作,因为您需要锁定引用计数访问。)
          • 使用良好的哈希表代替 std::set 和 std::map。
          • “Java”风格的迭代器,可以作为单个对象传递
          • 不需要知道容器类型的迭代器类型(为了更好的编译时代码解耦)
          • 具有更多实用功能的字符串类
          • 矢量容器中的可配置边界检查。 (所以不是 [] 或 .at,而是带有编译或运行时标志的相同方法,用于从“安全”模式转到“快速”模式)
          • 容器设计用于使用指向将删除其内容的对象的指针。

          【讨论】:

          • 实际上,我会感到惊讶。 STL 通常也经过高度优化。
          • 我击败了 STL,我什至没有尝试编写优化的库。
          【解决方案15】:

          缺点:

          您正在引入对您自己的新库的依赖。即使这已经足够了,并且您的实现工作正常,您仍然有依赖关系。这可能会在代码维护方面给您带来很大的麻烦。其他人(包括您自己,在一年甚至一个月内)都不会熟悉您独特的字符串行为、特殊迭代器等。在您开始重构/扩展任何东西之前,需要付出很多努力才能适应新环境。 如果您使用 STL 之类的东西,那么每个人都已经知道它了,它被很好地理解和记录,没有人需要重新学习您的自定义一次性环境。

          【讨论】:

          • 一个很好的答案。仅使用 STL 将具有通用知识的优势。
          【解决方案16】:

          我认为你应该这样做。

          我相信我会为此大吃一惊,但你知道,这里的每个 C++ 程序员都喝了太多的 STLcoolaid。

          STL 是一个很棒的库,但我从第一手经验中知道,如果你自己开发,你可以:

          1) 对于您的特定用例,使其比 STL 更快。 2)您将编写一个仅包含所需接口的库。 3)您将能够扩展所有标准的东西。 (我无法告诉你我多么希望 std::string 有一个 split() 方法)...

          每个人都说这需要大量工作是对的。没错。

          但是,你会学到很多东西。即使你写完之后再回到 STL 不再使用它,你仍然会学到很多东西。

          【讨论】:

          • 很好的答案 :) 我敢肯定,我什至会因为问这个问题而受到抨击!
          • 这里不是每个程序员。 :-) STL 很棒——但如果我在它出现之前没有编写自己的版本,我就不会理解所涉及的设计决策,或者为什么在不同情况下使用某些容器而不是其他容器。
          • 您将能够纠正我对 STL 的一些小烦恼。例如,您可以在 O(1) 中实现 size() 方法,而不是 O(N)!
          【解决方案17】:

          看来您更新了问题,所以现在确实有两个问题:

          1. 如果我认为 std:: 库对我的需求来说太复杂了,我该怎么办?

          设计您自己的类,在内部使用相关的 std:: 库功能为您完成“繁重的工作”。这样您就不会出错,而且您仍然可以发明自己的编码接口。

          1. 如果我想了解数据结构的工作原理,应该怎么做?

          从头开始设计您自己的一组数据结构类。然后试着弄清楚为什么标准的更好。

          【讨论】:

            【解决方案18】:

            您可能对EASTL 感兴趣,这是不久前记录的对 STL Electronic Arts 的重写。他们的设计决策主要是由多平台视频游戏编程中的特定愿望/需求驱动的。链接文章中的摘要很好地总结了它。

            【讨论】:

              【解决方案19】:

              我的一点经验:不久前,我实现了自己的类矢量类,因为我需要对其进行良好的控制。

              由于需要通用性,我制作了一个模板化数组。

              我还想不使用 operator[] 来迭代它,而是像使用 C 一样增加一个指针,所以我不会在每次迭代时计算 T[i] 的地址......我添加了两个方法一个返回指向分配内存的指针和另一个返回指向末尾的指针。 要遍历一个整数数组,我必须写这样的东西:

              for(int * p = array.pData(); p != array.pEnd(); ++p){
                cout<<*p<<endl; 
              }
              

              然后当我开始使用向量的向量时,我发现如果有可能 a 可以分配一大块内存而不是多次调用 new 。这时候我在模板类中添加了一个分配器。

              直到那时我才注意到我写了一个完全没用的 std::vector 克隆。

              至少现在我知道我为什么使用 STL...

              【讨论】:

                【解决方案20】:

                例如,使用 STL 会吐出 大量无法理解和损坏的 编译器错误

                其原因本质上是 C++ 模板。如果您使用模板(如 STL 那样),您将收到大量难以理解的错误消息。因此,如果您实现自己的基于模板的集合类,您将不会处于更好的位置。

                您可以制作非基于模板的容器并将所有内容存储为 void 指针或某些基类,例如但是你会失去编译时类型检查,并且 C++ 作为一种动态语言很糟糕。这样做并不像在 e.g. 中那样安全。 Objective-C、Python 或 Java。原因之一是 C++ 没有所有类的根类,无法对所有对象进行所有自省以及运行时的一些基本错误处理。相反,如果您的类型有误,您的应用程序可能会崩溃和烧毁,而且您不会得到任何错误线索。

                【讨论】:

                  猜你喜欢
                  • 2012-11-06
                  • 2014-02-27
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-05-04
                  • 2014-12-23
                  • 1970-01-01
                  相关资源
                  最近更新 更多