使用 MISRA C++:2023® 避免基于范围的 for 循环中的错误

描述

MISRA C++:2023®,MISRAC++标准的下一个版本,就在这里!为了帮助您了解 MISRA C++:2023 与上一版本之间的变化,我们继续 Perforce 首席技术支持工程师 Frank van den Beuken 博士撰写的第三期博客系列。

在前两篇博客中,我们 向您介绍了新的 MISRA C++ 标准 和 C++ 的历史 。在这篇博客中,我们将仔细研究以 C++ 中 for 循环为中心的特定规则。

 

什么是 MISRA C++:2023 Rule 9.5.2,为什么它很重要?

MISRA C++:2023 引入了规则 9.5.2,“ for 范围初始值设定项 最多应包含一个函数调用”,以避免在基于范围的 for 语句的 for 范围初始值设定项创建临时对象时可能发生的未定义行为。

为了理解为什么会发生这种情况,让我们仔细看看基于 C++ 范围的 for 循环。

 

什么是 C++ 中基于范围的 for 循环?

在编程中,循环用于重复代码块。当您知道要在代码块中循环多少次时,请使用for循环。

C++ 基于范围的 for 循环是在 C++11 中引入的,作为容器迭代的简洁表示法。

传统循环源自 C 语言,具有可选的循环初始化,然后是循环条件,最后是循环增量表达式。 

传统for循环可用于迭代容器,如下所示: 

std::vector v = { "Example", "vector", "of", "strings" }; 
for ( auto &&i = v.begin(); i != v.end(); ++i ) { 
  std::cout << *i << “ “; 

std::cout << std::endl; 

使用基于范围的for时,迭代器的使用是隐式的: 

for ( auto &&s: v ) { 
  std::cout << s << “ “; 

对于同一循环,这是一个更简单的表示法。C++ 语言标准指出它是以下方面的缩写:


  auto && __range = v; 
  auto __begin = __range; 
  auto __end = v.end(); 
 
  for (; __begin != __end; ++__begin) { 
    auto &&s = *__begin; 
    std::cout << s << “ “; 
  } 

但是,这种表示法存在一定的局限性。在上面的示例中, __range 是用 v 初始化的,这是一个更简单的变量,但也可以使用一个复杂的表达式,为其创建多个临时对象。

让我们考虑使用一个函数,该函数返回字符串的向量,并具有:

  • 一个输出用空格分隔的字符串的循环,如上所述
  • 第二个循环,打印第一个字符串的字母,用空格分隔:
std::vector createStrings() { 
  return { "Example”, "vector", "of", "strings" }; 

int main() { 
  for ( auto w: createStrings() ) { std::cout << w << " "; } 
  std::cout << std::endl; 
  for ( auto c: createStrings()[0] ) { std::cout << c << " "; } 
  std::cout << std::endl; 

如果我们执行此操作,第一个循环将按预期运行,但第二个循环将调用 未定义的行为 。 问题是  createStrings()[0] 有两个函数调用。最里面的调用是 createStrings 的调用 ,最外面的调用是对索引运算符[ ]的调用。

未定义行为的原因是 “ createStrings ”返回的临时对象 用作“ operator[ ]”调用的参数,因此,根据 C++ 的规则,临时对象的生存期不会延长。

返回页首

 

MISRA C++:2023 Rule 9.5.2 如何防范未定义的行为

MISRA C++:2023 Rule 9.5.2 旨在防止这种情况。 MISRA C++:2023 引入了规则 9.5.2,该规则 要求 for范围初始值设定项 最多应包含一个函数调用。

它还建议通过在循环范围之前的单独声明中执行内部函数调用来解决此问题。例如:

auto strings = createStrings(); 
for ( auto c: strings[0] ) { std::cout << c << " "; } 

现在,初始值设定项中只有一个函数调用,因此生存期扩展具有所需的效果,并且行为已完全定义。 

请注意,此问题已在 C++23 中得到解决,其中初始值设定项的所有临时项的生存期已扩展到整个 for 语句。 

 

使用 Helix QAC 执行 MISRA C++:2023 规则

Perforce 的 Helix QAC 是一种静态分析工具,在提供 MISRA C 和 MISRA C++ 合规性检查以及许多其他有价值的分析功能方面处于领先地位。 

Helix QAC 通过其标准合规性模块为 MISRA C++:2023 规则提供 100% 的强制执行覆盖率,现已推出。静态分析工具查找并报告 C 和 C++ 中违反 MISRA 规则和指令的情况。

欢迎联系北汇信息,申请Helix QAC试用。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分