0

我们正在制作一个可移植的代码(win+macOs),并且我们正在研究如何使代码更加健壮,因为它经常崩溃......(通常是溢出或错误的初始化):-(

我读到谷歌浏览器对每个标签都使用一个进程,所以如果出现问题,程序不会完全崩溃,只有那个标签。我认为这很整洁,所以我可以试一试!

所以我想知道是否有人有一些提示、帮助、阅读列表、评论或可以帮助我构建更多 rubust c++ 代码的东西(便携总是更好)。

在同一主题中,我还想知道是否有一个可移植的进程库(如 boost)?

非常感谢。

4

12 回答 12

5

Chrome 的答案更多的是关于故障缓解,而不是代码质量。做 Chrome 正在做的事情就是认输。

  1. 更好的质量保证不仅仅是程序员测试他们自己的工作。
  2. 单元测试
  3. 回归测试
  4. 阅读其他公司使用的最佳实践。

坦率地说,如果您的软件经常由于溢出和错误的初始化而崩溃,那么您将遇到一个非常基本的编程质量问题,并且不容易解决。这听起来很杂乱无章,这不是我的意图。我的观点是,错误代码的问题必须是您最关心的问题(我敢肯定)。诸如 Chrome 或自由使用异常处理来捕获程序缺陷之类的东西只会分散您对真正问题的注意力。

于 2008-09-17T16:17:49.193 回答
5

我开发了许多多平台 C++ 应用程序(最大的是 150 万行代码并在 7 个平台上运行——AIX、HP-UX PA-RISC、HP-UX Itanium、Solaris、Linux、Windows、OS X) . 实际上,您的帖子中有两个完全不同的问题。

  1. 不稳定。你的代码不稳定。修理它。

    • 使用单元测试在逻辑问题杀死你之前发现它们。
    • 如果不明显,请使用调试器找出导致崩溃的原因。
    • 使用 boost 和类似的库。特别是,指针类型将帮助您避免内存泄漏。
  2. 跨平台编码。

    • 同样,尽可能使用为此设计的库。特别是对于任何 GUI 位。
    • 尽可能使用标准(例如 ANSI 与 gcc/MSVC、POSIX 线程与 Unix 特定的线程模型等),即使它需要更多的工作。最小化特定于平台的代码意味着更少的整体工作,以及需要学习的 API 更少。
    • 隔离,隔离,隔离。尽可能避免针对不同平台的内联#ifdefs。相反,将特定于平台的代码粘贴到它自己的头文件/源代码/类中,并使用您的构建系统和#includes 来获取正确的代码。这有助于保持代码的清洁和可读性。
    • 尽可能使用 C99 整数类型,而不是“long”、“int”、“short”等——否则当你从 32 位平台移动到 64 位平台并且 long 突然改变时,它会咬你从 4 个字节到 8 个字节。而且,如果曾经将其写入网络/磁盘/等,那么您将遇到平台之间的不兼容问题。

就个人而言,我会先稳定代码(不添加任何更多功能),然后处理跨平台问题,但这取决于你。请注意,Visual Studio 有一个出色的调试器(正是因为这个原因,上面提到的代码库才被移植到 Windows)。

于 2008-09-17T17:09:16.903 回答
1

你没有提到目标项目是什么;每个选项卡都有一个进程并不一定意味着更“健壮”的代码。无论可移植性如何,您都应该致力于编写带有测试的可靠代码 - 只需阅读有关编写良好 C++ 代码的信息 :)

至于可移植性部分,请确保您从第一天起就在两个平台上进行测试,并确保在解决特定于平台的问题之前不编写新代码。

于 2008-09-17T16:09:47.013 回答
1

你真的,真的不想做 Chrome 正在做的事情,它需要一个进程管理器,这可能对你想要的东西来说太过分了。

您应该研究使用来自 Boost 的智能指针或其他将为 C++ 提供引用计数或垃圾收集的工具。

或者,如果您经常崩溃,您可能需要考虑使用具有 C++ 绑定的脚本语言编写应用程序的非性能关键部分。

于 2008-09-17T16:10:09.697 回答
1

Scott Meyers 的Effective C++More Effective C++非常好,而且读起来很有趣。

Steve McConnell 的Code Complete是许多人的最爱,包括 Jeff Atwood。

Boost 库可能是一个很好的选择。我工作的一个项目使用它们。我自己只使用过WIN32线程。

于 2008-09-17T16:15:26.470 回答
1

我同意托拉克的观点。

糟糕的初始化或溢出是代码质量差的迹象。

谷歌这样做是因为有时无法控制页面中执行的代码(由于插件错误等)。因此,如果您使用的是低质量插件(它确实发生了),也许 Google 解决方案对您有好处。

但是一个经常崩溃的没有插件的程序只是写得不好,或者非常非常复杂,或者非常老旧(并且缺少很多维护时间)。您必须停止开发,并调查每一次崩溃。在 Windows 上,使用 PDB(程序数据库)编译模块,每次崩溃时,附加一个调试器。

您还必须添加内部测试。避免模​​式:

doSomethingBad(T * t)
{
   if(t == NULL) return ;

   // do the processing.
}

这是一个非常糟糕的设计,因为错误就在那里,而这次你只是避免它。但是没有这个守卫的下一个函数会崩溃。最好尽快崩溃以离错误更近。

相反,在 Windows 上(MacOS 上必须有类似的 API)

doSomethingBad(T * t)
{
   if(t == NULL) ::DebugBreak() ; // it will call the debugger

   // do the processing.
}

(不要直接使用这段代码...把它放在一个define中以避免将其传递给客户端...)您可以选择适合您的错误API(异常,DebugBreak,assert等),但使用它在代码知道有问题的那一刻停止。

尽可能避免使用 C API。使用 C++ 习语(RAII 等)和库。

ETC..

PS:如果您使用异常(这是一个不错的选择),请不要将它们隐藏在 catch 中。你只会让你的问题变得更糟,因为错误就在那里,但程序会尝试继续,并且有时可能会在之后崩溃,同时破坏它所触及的任何东西。

于 2008-09-17T16:54:33.227 回答
0

你总是可以在你的程序中添加异常处理来捕捉这些类型的错误并忽略它们(尽管细节是特定于平台的)......但这非常是一把两刃剑。而是考虑让程序捕获异常并创建转储文件以进行分析。

如果您的程序以意想不到的方式运行,您对内部状态了解多少?也许崩溃的例程/线程损坏了一些关键数据结构?也许如果您发现错误并尝试继续,用户将保存他们正在处理的任何内容并将损坏提交到磁盘?

于 2008-09-17T16:12:38.317 回答
0

除了编写更稳定的代码之外,这里有一个可以回答您问题的想法。

无论您使用的是进程还是线程。您可以编写一个小/简单的看门狗程序。然后您的其他程序向该看门狗注册。如果任何进程死亡,或线程死亡,它可以由看门狗重新启动。当然,您需要进行一些测试以确保您不会继续重新启动相同的错误线程。即:重新启动它 5 次,然后在第 5 次之后,关闭整个程序并记录到文件/syslog。

于 2008-09-17T16:21:29.170 回答
0

使用调试符号构建您的应用程序,然后添加异常处理程序或配置 Dr Watson 以生成故障转储(运行 drwtsn32.exe /i 将其安装为调试器,无需 /i 即可弹出配置对话框)。当您的应用程序崩溃时,您可以通过查看调用堆栈和变量来检查它在 windbg 或 Visual Studio 中的问题所在。

谷歌符号服务器了解更多信息。

显然,您可以使用异常处理使其更健壮并使用智能指针,但最好修复错误。

于 2008-09-17T16:24:06.560 回答
0

构建它的想法是退出的唯一方法是让程序崩溃并且它可以随时崩溃。当你以这种方式构建它时,崩溃永远不会/几乎永远不会丢失任何数据。一两年前我读过一篇关于它的文章。可悲的是,我没有指向它的链接。

将其与某种故障转储相结合,并通过电子邮件发送给您,以便您解决问题。

于 2008-09-17T16:34:52.507 回答
0

我建议您编译一个 linux 版本并在Valgrind下运行它。

Valgrind 将跟踪内存泄漏、未初始化的内存读取和许多其他代码问题。我强烈推荐它。

于 2008-09-17T16:42:41.430 回答
0

经过超过 15 年的 Windows 开发,我最近编写了我的第一个跨平台 C++ 应用程序 (Windows/Linux)。就是这样:

  • STL
  • 促进。特别是文件系统和线程库。
  • 基于浏览器的 UI。该应用程序“执行”HTTP,其 UI 由 XHTML/CSS/JavaScript(Ajax 样式)组成。这些资源嵌入在服务器代码中,并在需要时提供给浏览器。
  • 丰富的单元测试。不完全是 TDD,但很接近。这实际上改变了我的发展方式。

我使用 NetBeans C++ 构建 Linux 并立即拥有完整的 Linux 端口。

于 2008-09-17T18:29:32.000 回答