这篇文章是由塞尔吉奥列霍夫和安德鲁帕多写的
这个 C++核心指南 通过提供广泛的建议,可以帮助您改进代码并降低维护成本:鼓励使用标准库,尽可能避免使用不安全的实践,保持一致的样式,以及帮助您执行合理的设计决策。对于那些拥有遗留代码的人来说,大量的核心指导方针和建议可能会让人气馁,但是即使是一个渐进的清理过程也会立即改进您的代码,而不需要完全重写。
我们在visualstudio中实现了一组代码分析检查,可以帮助您开始向更安全的代码方向发展。我们正在继续改进这些检查,并添加更多的C++核心指南的检查,但是当前的集合允许您今天开始工作,使现有代码更好,并采用新的编写现代C++的标准。
C++核心指南检查器不是新的:它首先作为NuGET包发布,并且 它包含在Visual Studio 2017中 . 它是在VisualStudio的所有版本中包含的C++代码分析工具之上的。
在Visual Studio 2017 15.3中,我们添加了更多检查并修复了几个错误。我们将在以后的博客文章中提供更多关于这些检查的细节。在这篇文章中,我们将快速了解如何使用这个工具,以及它可以捕捉到的问题。
运行C++核心指南检查器
棋盘格是棋盘的一部分 C++代码分析工具 . 假设我们有一个本地C++项目。要启用代码分析,我们可以使用IDE:
- 选择项目并在上下文菜单中选择“属性”。
- 在“配置属性”树中展开“代码分析”节点。
- 在“常规”选项卡上,选中“在生成时启用代码分析”。
- 切换到“扩展”节点并启用“C++核心检查(已发布)”。
- 保存属性。
- 现在,项目的每个有效构建(当有任何更改时)都应该使用扩展检查运行代码分析。
筛选规则
如果您对查看规则子集感兴趣,可以使用规则集管理您将看到的项目警告。使用相同的“通用”选项卡(参见“如何运行C++核心检查”)来选择适当的规则集,然后重建项目:
通过将宏与 #pragma警告 . 例如,下面介绍如何仅启用类型安全规则:
#include <CppCoreCheck/Warnings.h>#pragma warning(disable: ALL_CPPCORECHECK_WARNINGS)#pragma warning(default: CPPCORECHECK_CONST_WARNINGS)
您还可以启用单个规则,以便在代码生成大量结果时更易于处理:
#pragma warning(default: WARNING_NO_REINTERPRET_CAST)
C++核心指南检查器发现的问题
C++核心指南检查器可以检测到什么样的问题?以下是检查器中可用的规则示例。这些规则检测到的问题通常是有范围的,并且可以在没有大量代码搅动的情况下修复。您可以关注一种警告,然后一次解决一个文件。
下面的一些修复程序使用了一个小型的工具库,称为 指南支持库 ,设计支持C++核心指南。
- 不安全的类型转换:
// Don't use reinterpret_cast. It is hard to maintain safely.auto data = reinterpret_cast<char*>(buffer);
可以在此处应用以下修复:
// To avoid buffer overruns use gsl::as_writeable_bytes which returns gsl::span.auto data = gsl::as_writeable_bytes<int>(gsl::make_span(buffer));
- 不安全的低级资源管理:
// Avoid calling new and delete explicitly. Unique pointers are safer.auto buffer = new int[buffer_size];if (read_data(buffer, buffer_size) == read_status::insufficient_space) // Likely leaking memory here unless read_data deallocates it. buffer = new int[max_buffer_size];if (read_data(buffer, max_buffer_size) == read_status::insufficient_space){ delete[] buffer; return nullptr;}
为了避免内存管理出现问题,我们可以重写以下代码:
// std::unique_pointer will own and manage this object and dispose of itauto buffer = std::make_unique<int[]>(buffer_size);if (read_data(buffer.get(), buffer_size) == read_status::insufficient_space) buffer = std::make_unique<int[]>(max_buffer_size);if (read_data(buffer.get(), max_buffer_size) == read_status::insufficient_space) return nullptr;
- 缺少常量规范,这可能导致在以后的代码更改中发生意外的数据修改:
// If variable is assigned only once, mark it as const.auto buffer_size = count * sizeof(data_packet);auto actual_size = align(buffer_size);if (use_extension) actual_size += extension_size;encrypt_bytes(buffer, actual_size);
解决方法很简单:
// Now buffer_size is protected from unintentional modifications.const auto buffer_size = count * sizeof(data_packet);
- C++核心指南检查器甚至可以检测许多复杂的问题,例如在代码路径中缺少资源清理的代码。在本例中,代码使用
gsl::owner
类型从C++核心指南GSL。gsl::owner<int*> sequence = GetRandomSequence(); // This is not released.try{ StartSimulation(sequence);}catch (const std::exception& e){ if (KnownException(e)) return; // Skipping resource cleanup here. ReportException(e);}delete [] sequence;
在这种情况下
GetRandomSequence()
应该重新设计为返回智能指针而不是gsl::owner
这样当它超出范围时就会自动释放。
最后
好的工具可以帮助您维护和升级代码。C++核心指南是一个很好的开始,C++核心指南检查器可以帮助您清理代码并保持代码整洁。试用VisualStudio 2017中的C++核心指南检查器,让我们知道你的想法!
如果您对我们有任何反馈或建议,请告知我们。我们可以通过以下评论和电子邮件联系到您( visualcpp@microsoft.com )你可以通过 帮助>报告产品中的问题 ,或通过 开发者社区 . 你也可以在Twitter上找到我们( @视觉 )还有Facebook( msftvisualcpp软件 ).