9

虽然 C++ 标准委员会努力定义其复杂但强大的特性并保持其与 C 的向后兼容性,但根据我的个人经验,由于缺乏工具,我发现使用 C++ 编程的许多方面都很麻烦。

例如,我最近尝试重构一些 C++ 代码,将许多 shared_ptr 替换为 T& 以删除大型库中不需要的指针用法。我不得不手动执行几乎整个重构,因为没有任何重构工具可以帮助我安全地完成这项工作。

使用调试器处理 STL 数据结构就像是在陌生人不同意时找出她的电话号码。

根据您的经验,C++ 中缺少哪些必要的开发人员工具?

4

12 回答 12

26

我梦想的工具将是一个编译时模板调试器。可以让我以交互方式逐步完成模板实例化并在实例化时检查类型,就像常规调试器在运行时所做的那样。

于 2009-08-10T18:23:33.970 回答
11

根据您的经验,C++ 中缺少哪些必要的开发人员工具?

代码完成。严重地。重构是一个不错的功能,但我认为代码完成对于 API 的可发现性和可用性来说更为基础和重要。

基本上,需要任何不了解 C++ 代码的工具都很糟糕。

于 2009-08-10T18:02:25.883 回答
8

类方法的代码生成。当我输入声明时,您应该能够弄清楚定义。当我谈到这个话题时,我们可以修复“goto 声明/goto 定义”总是去声明吗?

重构。是的,我知道由于预处理器的原因,这在形式上是不可能的——但编译器在搜索和替换变量名方面仍然可以做得比我做的更好。您还可以在使用时语法突出显示本地、成员和参数。

皮棉。那么我刚刚定义的变量会影响更高的变量吗?C 会在 1979 年告诉我,但 2009 年的 C++ 显然更喜欢我自己找出答案。

一些体面的错误信息。如果我保证永远不会在类的方法中定义具有相同名称的类 - 你是否保证告诉我缺少的“}”。事实上,编译器可以了解一些历史知识吗?所以如果我在以前工作的文件中添加了不平衡的“{”或“(”,我们是否可以考虑在消息中提及这一点?

STL 错误消息能否(抱歉引用另一条评论)看起来不像您阅读“/dev/random”,卡在前面的“!/bin/perl”然后通过结果运行税码?

一些有用的东西的警告怎么样?“整数用作布尔性能警告”没有用,它不会产生任何性能差异,我别无选择 - 这是库所做的,你已经告诉我 50 次了。但是如果我错过了一个“;” 从类声明的末尾或方法定义的末尾的“}”开始,您不会警告我-您会竭尽全力找到最不可能(但理论上)正确的方法来解析结果。
就像这个浏览器中内置的拼写检查器一样,它很高兴地接受我拼写错误的天气(因为拼写是阉割的雄性山羊的古老术语!我写了多少次关于女高音食草动物的文章?)

拼写检查怎么样?40 年前,大型机 Fortran 编译器进行了拼写检查,因此如果拼写错误的“WRITE”,您不会在第二天回来看到一堆卡片和一条流鼻涕的错误消息。您收到警告说“WRIET”已在第 X 行更改为 WRITE。现在编译器愉快地继续并花费 10 分钟构建一些大型浏览文件和调试器输出,然后告诉您您在 10,000 行前拼错了 prinft。

附言。是的,其中很多只适用于 Visual C++。

pps。是的,他们现在带着我的药来。

于 2009-08-10T18:59:36.020 回答
6

C++ 的主要问题是难以解析。这就是为什么很少有工具可以处理源代码。(这也是为什么我们会遇到一些编译器历史上最可怕的错误消息。)结果是,除了极少数例外(我只知道 doxygen 和 Visual Assist),这取决于实际的编译器支持帮助我们编写和按摩代码所需的一切。由于编译器传统上是相当精简的命令行工具,因此构建丰富的编辑器支持的基础非常薄弱。

大约十年来,我一直在使用 VS。同时,它的代码补全几乎可用。(是的,我正在研究双核机器。否则我不会这么说,不是吗?)如果您使用 Visual Assist,代码完成实际上是相当不错的。如今,VS 本身和 VA 都带有一些基本的重构。这也几乎可以用于它的目标(尽管它仍然明显低于代码完成)。当然,超过 15 年的重构,搜索和替换是盒子中唯一的工具,与其他语言相比,我的需求可能过于恶化,所以这可能意义不大。

然而,我真正缺乏的仍然是:在我的代码移植到的所有平台上完全符合标准的编译器和标准库实现。我说的是在上一个标准发布后 10 年以上,在下一个标准发布前大约一年!(仅补充一点:C++1x 在 2011 年被广泛采用。

一旦解决了这些问题,就会时不时地提到一些事情,但是哪些供应商仍在努力遵守超过 10 年的标准(或者,实际上某些功能就是这样,甚至放弃了它),从来没有真正解决:

  • 可用的、合理的、可理解的编译器消息(como实际上相当不错,但前提是你将它与其他C++编译器进行比较);一个链接器,它不只是举手并说“出了点问题,我无法继续”(如果您将 C++ 作为第一语言教授,您就会明白我的意思);概念('nuff 说)
  • 一个 IO 流实现,它不会抛弃重载operator<<()通过调用底层运行时解析给我们带来的所有编译时优势printf()(Dietmar Kühl 曾经打算这样做,不幸的是,他的实现在没有技术的情况下死了越来越普遍)
  • 所有平台上的 STL 实现都提供了丰富的调试支持(Dinkumware在这方面已经相当不错了)
  • 所有平台上的标准库实现,使用书中的每一个技巧,在编译时和运行时给我们更严格的检查和更高的性能(你知道 yasli 发生过什么吗?)
  • 调试模板元程序的能力(是的,jalf 已经提到了这一点,但不能经常说)
  • 使工具变得lint无用的编译器(无需担心,lint供应商,这只是一厢情愿)

如果所有这些以及我忘记提及(随意添加)的许多其他问题都已解决,那么获得几乎与 Java 或 C# 几乎在同一个联盟中的重构支持将是一件好事。但也只有那时。

于 2009-08-10T19:52:15.367 回答
6

如果谈论 MS Visual Studio C++,Visual Assist是一个非常方便的代码完成工具,一些重构 - 例如重命名所有/选定的引用,find/goto 声明,但我仍然怀念 JBuilder 或 IntelliJ 等 Java IDE 的丰富性。

我仍然想念的是一个语义差异工具——你知道,它不会逐行比较两个文件,而是语句/表达式。我在互联网上找到的只是一些废弃的尝试——如果你知道,请写在评论中

于 2009-08-10T19:57:32.393 回答
5

试图优化编译模型的编译器。

与其根据需要天真地包含头文件,在每个编译单元中再次解析它们,为什么不先解析头文件一次,为它们构建完整的语法树(这必须包括预处理器指令,因为我们还不知道定义了哪些宏),然后只要包含标题就简单地遍历该语法树,应用已知的#defines 来修剪它。

它甚至可以用作预编译头文件的替代品,因此每个头文件都可以单独预编译,只需将此语法树转储到磁盘即可。我们不需要一个单一且容易出错的预编译头文件,并且会在重建时获得更精细的粒度,即使修改了头文件也尽可能少地重建。

就像我的其他建议一样,这将需要大量的工作来实现,但我看不出有任何基本问题使它成为不可能

似乎它可以显着加快编译时间,几乎使它与头文件的数量呈线性关系,而不是在#includes 的数量上。

于 2009-08-10T20:26:47.123 回答
4

快速可靠的索引器。大多数花哨的功能都是在此之后出现的。

于 2009-08-10T18:25:45.230 回答
4

执行编码标准的常用工具。
采用所有通用标准,并允许您根据项目的需要打开/关闭它们。

目前只有一堆 perl 脚本 usullay 必须替代。

于 2009-08-10T19:27:11.267 回答
3

我对 C++ 工具的状态非常满意。我唯一能想到的是在 VS/gcc 中默认安装 Boost。

于 2009-08-10T18:26:11.687 回答
3

重构,重构,重构。并在打字时进行编译。对于重构,我至少遗漏了大多数现代 Java IDE 可以做的事情的一半。虽然 Visual Assist X 走了很长一段路,但缺少很多重构。编写 C++ 代码的任务仍然差不多。编写 C++ 代码。IDE 支持的高级重构越多,它就越容易构建,结构的可塑性越强,就越容易迭代结构并对其进行改进。拿起 Intellij 的演示版,看看你缺少什么。这些只是我几年前记得的一些。

  • 提取接口:查看具有通用接口的类,将通用函数移动到接口类中(对于 C++,这将是一个抽象基类)并将指定的函数派生为抽象

  • Better extract method: mark a section of code and have the ide write a function that executes that code, constructing the correct parameters and return values

  • Know the type of each of the symbols that you are working with so that not only command completion can be correct for derived values e.g. symbol->... but also only offer functions that return the type that can be used in the current expression e.g. for

    UiButton button = window->...

At the ... only insert functions that actually return a UiButton.

于 2009-08-10T19:26:01.037 回答
2

一个独立的工具:命名约定。

于 2009-08-10T18:36:28.437 回答
2

智能智能感知/代码完成,即使是模板繁重的代码。

当您在函数模板中时,编译器当然不能确定模板参数的任何内容(至少不能没有概念),但它应该能够做出很多猜测和估计。根据函数中类型的使用方式,它应该能够缩小可能的类型,实际上是一种保守的临时概念。如果函数中的一行在模板类型上调用 .Foo() ,显然 Foo 成员方法必须存在,并且 Intellisense 也应该在函数的其余部分中建议它。

它甚至可以查看从哪里调用函数,并使用它来确定至少一种有效的模板参数类型,并在此基础上简单地在函数内部提供 Intellisense。

如果使用 aint作为模板参数调用该函数,那么显然,使用 ofint必须是有效的,因此 IDE 可以将其用作函数内部的“样本类型”并基于此提供 Intellisense 建议。

JavaScript 刚刚在 VS 中得到了 Intellisense 的支持,不得不克服很多类似的问题,所以可以做到。当然,以 C++ 的复杂程度,这将是一个荒谬的工作量。但这将是一个不错的功能。

于 2009-08-10T20:02:54.190 回答