检查仅标头的C ++库(awesome-hpp)

PVS-Studio和真棒hpp


不幸的是,我们检查了“ Awesome hpp”集合中的大多数库。这些是仅由头文件组成的小型C ++项目。希望发现的错误将有助于使这些库更好。如果他们的作者开始定期免费免费使用PVS-Studio分析仪,我们也将感到高兴。



我提醒您注意检查awesome-hpp精湛的纯标题C ++库的精选列表)列表中列出的各种库的结果



我首先从“跨平台移动电话播客中了解了此列表借此机会,我建议所有C ++程序员熟悉CppCastCppCast是C ++开发人员针对C ++开发人员的第一个播客!



尽管列表中有大量项目,但几乎没有错误。这有三个原因:



  • 这些是非常小的项目。从字面上看,许多文件都由一个头文件组成。
  • 我们尚未检查所有项目。其中一些编译存在问题,我们决定跳过它们。
  • 通常,为了了解模板类/函数中是否存在错误,必须实例化它们。因此,当库被积极使用时,只有在该项目中分析仪才能检测到许多错误。我们只是将头文件包含在一个空的.cpp文件中并进行了检查,这使得检查无效。


但是,在研究警告的过程中,有足够的警告要撰写这篇文章以及另外一些警告。



给我的同事的提示
, - . . awesome-hpp, :



  • , C++11, C++14 C++17;
  • " , ";
  • " — , ";
  • ;
  • (. CSV Parser);
  • , . — , - :);
  • , .




库开发人员注意事项。有兴趣的人可以免费使用PVS-Studio分析仪检查开源项目。要获得您的开源项目的许可证,请填写此表格



现在,让我们最后看一下在某些库中发现的内容。



发现的错误



图书馆



iutest 库的简要说明
iutest是用于编写C ++测试的框架。
template<typename Event>
pool_handler<Event> & assure() {
  ....
  return static_cast<pool_handler<Event> &>(it == pools.cend() ?
    *pools.emplace_back(new pool_handler<Event>{}) : **it);
  ....
}


PVS-Studio警告V1023通过“ emplace_back”方法将没有所有者的指针添加到“池”容器中。发生异常时会发生内存泄漏。entt.hpp 17114



该代码可能会泄漏内存。如果容器需要重新分配,并且不能为新数组分配内存,则它将引发异常并且指针将丢失。



也许,对于测试而言,这种情况是不太可能的,而不是至关重要的。但是,我决定出于教育目的提及此缺点:)。



正确的选项:



pools.emplace_back(std::make_unique<pool_handler<Event>>{})


另一个相似的地方:V1023通过'emplace_back'方法将没有所有者的指针添加到'pools'容器中。发生异常时会发生内存泄漏。entt.hpp 17407



Jsoncons库



jsoncons 库的简短描述
一个C ++,仅标头的库,用于构建JSON和类似JSON的数据格式,并带有JSON指针,JSON补丁,JSONPath,JMESPath,CSV,MessagePack,CBOR,BSON,UBJSON。
第一个错误



static constexpr uint64_t basic_type_bits = sizeof(uint64_t) * 8;

uint64_t* data() 
{
  return is_dynamic() ? dynamic_stor_.data_ : short_stor_.values_;
}

basic_bigint& operator<<=( uint64_t k )
{
  size_type q = (size_type)(k / basic_type_bits);
  ....
  if ( k )  // 0 < k < basic_type_bits:
  {
    uint64_t k1 = basic_type_bits - k;
    uint64_t mask = (1 << k) - 1;             // <=
    ....
    data()[i] |= (data()[i-1] >> k1) & mask;
    ....
  }
  reduce();
  return *this;
}


PVS-Studio警告V629考虑检查“ 1 << k”表达式。32位值的位移,随后扩展为64位类型。bigint.hpp 744



此错误已经在文章“为什么对添加到项目中的开源库进行静态分析很重要”中详细讨论过简而言之,为了获得正确的掩码值,您需要这样编写:



uint64_t mask = (static_cast<uint64_t>(1) << k) - 1;


或像这样:



uint64_t mask = (1ull << k) - 1;


与第一个错误完全相同的错误可以在这里看到:V629考虑检查'1 << k'表达式。32位值的位移位,随后扩展为64位类型。bigint.hpp 779



第二个错误



template <class CharT = typename std::iterator_traits<Iterator>::value_type>
typename std::enable_if<sizeof(CharT) == sizeof(uint16_t)>::type 
next() UNICONS_NOEXCEPT
{
    begin_ += length_;
    if (begin_ != last_)
    {
        if (begin_ != last_)
        {
  ....
}


PVS-Studio警告V571重复检查。'if(begin_!= Last_)'条件已在第1138行中得到验证。unicode_traits.hpp 1140



Strange retest 有人怀疑这里有错别字,第二个条件看起来应该有所不同。



Clipp库



clipp 库的简短描述
clipp-现代C ++的命令行界面。单个头文件中包含的C ++ 11/14/17易于使用,功能强大且表现力强的命令行参数处理。
inline bool
fwd_to_unsigned_int(const char*& s)
{
  if(!s) return false;
  for(; std::isspace(*s); ++s);
  if(!s[0] || s[0] == '-') return false;
  if(s[0] == '-') return false;
  return true;
}


PVS-Studio警告V547表达式的[0] =='-”始终为false。clipp.h 303



实际上,这不是错误,而只是冗余代码。减号检查执行两次。



SimpleIni库



SimpleIni 库的简短描述
一个跨平台的库,提供一个简单的API来读取和写入INI样式的配置文件。它支持ASCII,MBCS和Unicode数据文件。
#if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux))


PVS-Studio警告V1040预定义宏名称的拼写可能有错字。“ _linux”宏类似于“ __linux”。SimpleIni.h 2923



最有可能的是,_linux的名称缺少一个下划线,应使用__linux的名称但是,在POSIX中,不建议使用此宏,最好使用__linux__



CSV解析器库



CSV分析器 库的简要说明
一个现代的C ++库,用于读取,编写和分析CSV(及类似)文件。
CSV_INLINE void CSVReader::read_csv(const size_t& bytes) {
  const size_t BUFFER_UPPER_LIMIT = std::min(bytes, (size_t)1000000);
  std::unique_ptr<char[]> buffer(new char[BUFFER_UPPER_LIMIT]);
  auto * HEDLEY_RESTRICT line_buffer = buffer.get();
  line_buffer[0] = '\0';
  ....
  this->feed_state->feed_buffer.push_back(
    std::make_pair<>(std::move(buffer), line_buffer - buffer.get())); // <=
  ....
}


PVS-Studio警告V769 “ line_buffer-buffer.get()”表达式中的“ buffer.get()”指针等于nullptr。结果值是没有意义的,不应使用。csv.hpp 4957



一个有趣的情况,需要仔细考虑。因此,我决定为此写一个单独的小笔记。另外,在尝试类似的代码时,我发现PVS-Studio本身存在缺陷:)。在某些情况下,尽管它应该发出警告,但它是沉默的。



简而言之,此代码是否起作用取决于参数的求值顺序。参数的计算顺序取决于编译器。



PPrint库



PPRINT 库的简要说明:。
适用于现代C ++的漂亮打印机。
template <typename Container>
typename std::enable_if<......>::type print_internal(......) {
  ....
  for (size_t i = 1; i < value.size() - 1; i++) {
    print_internal(value[i], indent + indent_, "", level + 1);
    if (is_container<T>::value == false)
      print_internal_without_quotes(", ", 0, "\n");
    else
      print_internal_without_quotes(", ", 0, "\n");
  }
  ....
}


PVS-Studio警告V523'then '语句等效于'else'语句。pprint.hpp 715



无论情况如何,都执行相同的操作非常奇怪。也没有特殊的解释性注释。这与复制粘贴错误非常相似。



类似警告:



  • V523'then'语句等效于'else'语句。pprint.hpp 780
  • V523'then'语句等效于'else'语句。pprint.hpp 851
  • V523'then'语句等效于'else'语句。第927章
  • V523'then'语句等效于'else'语句。pprint.hpp 1012


Strf库



Strf 库的简短描述
一个快速的C ++格式库,支持编码转换。
第一个错误



template <int Base>
class numpunct: private strf::digits_grouping
{
  ....
  constexpr STRF_HD numpunct& operator=(const numpunct& other) noexcept
  {
    strf::digits_grouping::operator=(other);
    decimal_point_ = other.decimal_point_;
    thousands_sep_ = other.thousands_sep_;
  }
  ....
};


PVS-Studio警告V591非无效函数应返回一个值。numpunct.hpp 402



我们忘记在函数末尾写“ return * this;”。



第二个类似的错误



template <int Base>
class no_grouping final
{
  constexpr STRF_HD no_grouping& operator=(const no_grouping& other) noexcept
  {
    decimal_point_ = other.decimal_point_;
  }
  ....
}


PVS-Studio警告V591非无效函数应返回一个值。528。



指标库



指标 库的简要说明
现代C ++活动指标。
static inline void move_up(int lines) { move(0, -lines); }
static inline void move_down(int lines) { move(0, -lines); }   // <=
static inline void move_right(int cols) { move(cols, 0); }
static inline void move_left(int cols) { move(-cols, 0); }


PVS-Studio警告V524奇怪的是,“ move_down”功能的主体与“ move_up”功能的主体完全等效。indicator.hpp 983



我不确定这是否是错误。但是代码非常可疑。很有可能复制了move_up函数,并且其名称更改为move_down但是他们忘记删除负号。值得检查一下这段代码。



注意。如果代码正确,则需要了解它不仅会误导代码分析器,而且还会误导要使用或开发此代码的第三方程序员。在此代码中添加注释很有用。



清单库



清单 库的简短描述
manif是仅用于标头的C ++ 11 Lie理论库,用于针对机器人应用程序的状态估计。
template <typename _Derived>
typename LieGroupBase<_Derived>::Scalar*
LieGroupBase<_Derived>::data()
{
  return derived().coeffs().data();
}

template <typename _Derived>
const typename LieGroupBase<_Derived>::Scalar*
LieGroupBase<_Derived>::data() const
{
  derived().coeffs().data(); // <=
}


PVS-Studio警告V591非无效函数应返回一个值。lie_group_base.h 347



正确实现了非常数函数,但常数函数却没有正确实现。它是如何发生的甚至很有趣...



FakeIt库



FakeIt 库的简短描述
FakeIt是一个简单的C ++模拟框架。它支持GCC,Clang和MS Visual C ++。FakeIt用C ++ 11编写,可用于测试C ++ 11和C ++项目。
template<typename ... arglist>
struct ArgumentsMatcherInvocationMatcher :
         public ActualInvocation<arglist...>::Matcher {
  ....
  template<typename A>
  void operator()(int index, A &actualArg) {
      TypedMatcher<typename naked_type<A>::type> *matcher =
        dynamic_cast<TypedMatcher<typename naked_type<A>::type> *>(
          _matchers[index]);
      if (_matching)
        _matching = matcher->matches(actualArg);
  }
  ....
  const std::vector<Destructible *> _matchers;
};


PVS-Studio警告V522可能会取消引用潜在的空指针“匹配器”。fakeit.hpp 6720匹配器



指针使用dynamic_cast运算符返回的值初始化并且此运算符可以返回nullptr,这是很可能的情况。否则,使用static_cast而不是dynamic_cast更有效 有人怀疑病情有错别字,实际上应该写成:







if (matcher)
  _matching = matcher->matches(actualArg);


GuiLite图书馆



GuiLite 库的简短描述
所有平台上最小的仅标头GUI库(4 KLOC)。
#define CORRECT(x, high_limit, low_limit)  {\
  x = (x > high_limit) ? high_limit : x;\
  x = (x < low_limit) ? low_limit : x;\
}while(0)

void refresh_wave(unsigned char frame)
{
  ....
  CORRECT(y_min, m_wave_bottom, m_wave_top);
  ....
}


PVS-Studio警告V529奇数分号';'在“ while”运算符之后。 GuiLite.h 3413



宏中的错误不会导致某些问题。但这仍然是一个错误,因此我决定在文章中对其进行描述。



计划在宏(....)中使用经典模式do {...}。这使您可以在一个程序段中执行多个动作,同时可以在宏后面写一个分号“;”以实现美观,就好像它是一个函数调用一样。



但是在所考虑的宏中,他们意外地忘记写了do关键字。结果,宏似乎分为两部分。首先是街区。第二个是空的非执行循环:while(0); ...



那是什么问题呢?



例如,此类宏不能用于以下结构:



if (A)
  CORRECT(y_min, m_wave_bottom, m_wave_top);
else
  Foo();


该代码将被扩展为:



if (A)
  { ..... }
while(0);
else
  Foo();


同意,最好在库开发阶段而不是在使用阶段发现并解决此问题。应用静态代码分析:)。





PpluX库



PpluX 库的简要说明
用于线程调度,渲染等的单头C ++库...
struct DisplayList {
  DisplayList& operator=(DisplayList &&d) {
    data_ = d.data_;
    d.data_ = nullptr;
  }
  ....
}


PVS-Studio警告V591非无效函数应返回一个值。px_render.h 398



环球图书馆



通用库的简短描述:
通用数字(或称通用数字)的目标是,用并发执行环境中效率更高且数学上一致的数字系统代替IEEE浮点数。
第一个错误



template<typename Scalar>
vector<Scalar> operator*(double scalar, const vector<Scalar>& v) {
  vector<Scalar> scaledVector(v);
  scaledVector *= scalar;
  return v;
}


PVS-Studio警告V1001已分配“ scaledVector”变量,但在功能结束时未使用。vector.hpp 124错字



该函数需要返回一个新的矢量scaledVector 而不是原始的矢量v 在这里可以看到类似的拼写错误:V1001分配了'normalizedVector'变量,但未在函数末尾使用。vector.hpp 131第二个错误











template<typename Scalar>
class matrix {
  ....
  matrix& diagonal() {
  }
  ....
};


PVS-Studio警告V591非无效函数应返回一个值。matrix.hpp 109



第三错误



template<size_t fbits, size_t abits>
void module_subtract_BROKEN(
  const value<fbits>& lhs, const value<fbits>& rhs, value<abits + 1>& result)
{
  if (lhs.isinf() || rhs.isinf()) {
    result.setinf();
    return;
  }
  int lhs_scale = lhs.scale(),
      rhs_scale = rhs.scale(),
      scale_of_result = std::max(lhs_scale, rhs_scale);

  // align the fractions
  bitblock<abits> r1 =
    lhs.template nshift<abits>(lhs_scale - scale_of_result + 3);
  bitblock<abits> r2 =
    rhs.template nshift<abits>(rhs_scale - scale_of_result + 3);
  bool r1_sign = lhs.sign(), r2_sign = rhs.sign();
  //bool signs_are_equal = r1_sign == r2_sign;

  if (r1_sign) r1 = twos_complement(r1);
  if (r1_sign) r2 = twos_complement(r2);  // <=

  ....
}


PVS-Studio警告V581彼此并排放置的'if'语句的条件表达式相同。检查行:789,790。value.hpp 790



由复制粘贴引起的经典错误。我们乘以并乘以:



if (r1_sign) r1 = twos_complement(r1);


我们在其中将r1更改r2



if (r1_sign) r2 = twos_complement(r2);


他们忘记了 更改r1_sign正确的选项:



if (r2_sign) r2 = twos_complement(r2);


Chobo单头库



Chobo单头库的 简短描述
Chobolabs收集的小型单头C ++ 11库。
第一个错误



template <typename T, typename U, typename Alloc = std::allocator<T>>
class vector_view
{
  ....
  vector_view& operator=(vector_view&& other)
  {
    m_vector = std::move(other.m_vector);
  }
  ....
}


PVS-Studio警告V591非无效函数应返回一个值。vector_view.hpp 163



第二个错误



template <typename UAlloc>
vector_view& operator=(const std::vector<U, UAlloc>& other)
{
  size_type n = other.size();
  resize(n);
  for (size_type i = 0; i < n; ++i)
  {
    this->at(i) = other[i];
  }
}


PVS-Studio警告V591非无效函数应返回一个值。vector_view.hpp 184



图书馆PGM索引



PGM-index 库的简要说明
分段几何模型索引(PGM-index)是一种数据结构,它可以使用比传统索引少的数量级空间,对数十亿个项目的数组进行快速查找,前身,范围搜索和更新,同时提供相同的最坏情况查询时间保证...
第一个错误



char* str_from_errno()
{
#ifdef MSVC_COMPILER
  #pragma warning(disable:4996)
  return strerror(errno);
#pragma warning(default:4996)
#else
  return strerror(errno);
#endif
}


PVS-Studio警告V665在这种情况下,“#pragma警告(默认:X)”的用法可能不正确。应改用“ #pragma警告(按下/弹出)”。检查行:9170,9172。sdsl.hpp 9172



不正确的临时禁用编译器警告。这样的错误对于用户代码是可以原谅的。但是,仅标头库绝对不允许这样做。



第二个错误



template<class t_int_vec>
t_int_vec rnd_positions(uint8_t log_s, uint64_t& mask,
                        uint64_t mod=0, uint64_t seed=17)
{
  mask = (1<<log_s)-1;         // <=
  t_int_vec rands(1<<log_s ,0);
  set_random_bits(rands, seed);
  if (mod > 0) {
    util::mod(rands, mod);
  }
  return rands;
}


PVS-Studio警告V629考虑检查'1 << log_s'表达式。32位值的位移,随后扩展为64位类型。sdsl.hpp 1350



正确的选项之一:



mask = ((uint64_t)(1)<<log_s)-1;


Hnswlib库



Hnswlib 库的简短描述
具有python绑定的仅标头C ++ HNSW实现。HNSW 200M SIFT实验的论文代码。
template<typename dist_t>
class BruteforceSearch : public AlgorithmInterface<dist_t> {
public:
  BruteforceSearch(SpaceInterface <dist_t> *s, size_t maxElements) {
    maxelements_ = maxElements;
    data_size_ = s->get_data_size();
    fstdistfunc_ = s->get_dist_func();
    dist_func_param_ = s->get_dist_func_param();
    size_per_element_ = data_size_ + sizeof(labeltype);
    data_ = (char *) malloc(maxElements * size_per_element_);
    if (data_ == nullptr)
      std::runtime_error(
        "Not enough memory: BruteforceSearch failed to allocate data");
    cur_element_count = 0;
  }
  ....
}


PVS-Studio警告V596已创建对象,但未使用该对象。可能缺少'throw'关键字:throw runtime_error(FOO); bruteforce.h 26



忘记在std :: runtime_error之前编写throw语句



另一个此类错误:V596已创建对象,但未使用该对象。可能缺少'throw'关键字:throw runtime_error(FOO); 161章



tiny-dnn库



tiny-dnn库的 简短描述
tiny-dnn是深度学习的C ++ 14实现。它适合在有限的计算资源,嵌入式系统和IoT设备上进行深度学习。
第一个错误



class nn_error : public std::exception {
 public:
  explicit nn_error(const std::string &msg) : msg_(msg) {}
  const char *what() const throw() override { return msg_.c_str(); }

 private:
  std::string msg_;
};

inline Device::Device(device_t type, const int platform_id, const int device_id)
  : type_(type),
    has_clcuda_api_(true),
    platform_id_(platform_id),
    device_id_(device_id) {
  ....
#else
  nn_error("TinyDNN has not been compiled with OpenCL or CUDA support.");
#endif
}


PVS-Studio警告V596已创建对象,但未使用该对象。'throw'关键字可能丢失:throw nn_error(FOO); device.h 68



nn_error不是引发异常的函数,而只是一个类。因此,像这样使用它是正确的:



throw nn_error("TinyDNN has not been compiled with OpenCL or CUDA support.");


此类的另一个滥用:V596已创建对象,但未使用该对象。'throw'关键字可能丢失:throw nn_error(FOO); conv2d_op_opencl.h 136



第二个错误



inline std::string format_str(const char *fmt, ...) {
  static char buf[2048];

#ifdef _MSC_VER
#pragma warning(disable : 4996)
#endif
  va_list args;
  va_start(args, fmt);
  vsnprintf(buf, sizeof(buf), fmt, args);
  va_end(args);
#ifdef _MSC_VER
#pragma warning(default : 4996)
#endif
  return std::string(buf);
}


PVS-Studio警告V665在这种情况下,“#pragma警告(默认:X)”的用法可能不正确。应改用“ #pragma警告(按下/弹出)”。检查行:139,146。util.h 146



Dlib库



Dlib 库的简短描述
Dlib是一个现代的C ++工具箱,其中包含机器学习算法和工具,这些工具和工具可以用C ++创建复杂的软件来解决实际问题。
第一个错误



为了好玩,请尝试自行查找此错误。



class bdf_parser
{
public:

  enum bdf_enums
  {
    NO_KEYWORD = 0,
    STARTFONT = 1,
    FONTBOUNDINGBOX = 2,
    DWIDTH = 4,
    DEFAULT_CHAR = 8,
    CHARS = 16,
    STARTCHAR = 32,
    ENCODING = 64,
    BBX = 128,
    BITMAP = 256,
    ENDCHAR = 512,
    ENDFONT = 1024
  };
  ....
  bool parse_header( header_info& info )
  {
    ....
    while ( 1 )
    {
      res = find_keywords( find | stop );
      if ( res & FONTBOUNDINGBOX )
      {
          in_ >> info.FBBx >> info.FBBy >> info.Xoff >> info.Yoff;
          if ( in_.fail() )
              return false;    // parse_error
          find &= ~FONTBOUNDINGBOX;
          continue;
      }
      if ( res & DWIDTH )
      {
          in_ >> info.dwx0 >> info.dwy0;
          if ( in_.fail() )
              return false;    // parse_error
          find &= ~DWIDTH;
          info.has_global_dw = true;
          continue;
      }
      if ( res & DEFAULT_CHAR )
      {
          in_ >> info.default_char;
          if ( in_.fail() )
              return false;    // parse_error
          find &= ~DEFAULT_CHAR;
          continue;
      }
      if ( res & NO_KEYWORD )
          return false;    // parse_error: unexpected EOF
      break;
    }
  ....
};


找到了?



困惑的特拉沃尔塔-独角兽


她在这里:



if ( res & NO_KEYWORD )


PVS-Studio警告V616在按位运算中使用值为常数0的名为'NO_KEYWORD'的常数。fonts.cpp 288



命名的常量NO_KEYWORD的值为0。因此,该条件无意义。这样写是正确的:



if ( res == NO_KEYWORD )


在此找到另一个不正确的检查:V616在按位运算中使用值为0的名为'NO_KEYWORD'的常量。fonts.cpp 334



第二次错误



void set(std::vector<tensor*> items)
{
  ....
  epa.emplace_back(new enable_peer_access(*g[0], *g[i]));
  ....
}


PVS-Studio警告V1023通过“ emplace_back”方法将没有所有者的指针添加到“ epa”容器中。发生异常时会发生内存泄漏。tensor_tools.h 1665



为了了解问题所在,我建议熟悉V1023诊断程序的文档



第三个错误



template <
    typename detection_type, 
    typename label_type 
    >
bool is_track_association_problem (
  const std::vector<
    std::vector<labeled_detection<detection_type,label_type> > >& samples
)
{
  if (samples.size() == 0)
    return false;

  unsigned long num_nonzero_elements = 0;
  for (unsigned long i = 0; i < samples.size(); ++i)
  {
    if (samples.size() > 0)
      ++num_nonzero_elements;
  }
  if (num_nonzero_elements < 2)
    return false;
  ....
}


PVS-Studio警告V547表达式'samples.size()> 0'始终为true。svm.h 360



这是非常非常奇怪的代码!如果循环开始,则条件(samples.size()> 0)始终为true。因此,可以简化循环:



for (unsigned long i = 0; i < samples.size(); ++i)
{
  ++num_nonzero_elements;
}


在那之后,很明显根本不需要循环。可以更轻松,更有效地编写它:



unsigned long num_nonzero_elements = samples.size();


但是计划完成吗?该代码显然值得程序员认真研究。



第四个错误



class console_progress_indicator
{
  ....
  double seen_first_val;
  ....
};

bool console_progress_indicator::print_status (
  double cur, bool always_print)
{
  ....
  if (!seen_first_val)
  {
    start_time = cur_time;
    last_time = cur_time;
    first_val = cur;
    seen_first_val = true;  // <=
    return false;
  }
  ....
}


PVS-Studio警告V601布尔类型隐式转换为double类型。console_progress_indicator.h 136



true写入double类型的类的成员嗯...第五错误







void file::init(const std::string& name)
{
  ....
  WIN32_FIND_DATAA data;
  HANDLE ffind = FindFirstFileA(state.full_name.c_str(), &data);
  if (ffind == INVALID_HANDLE_VALUE ||
      (data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0)
  {
    throw file_not_found("Unable to find file " + name);                
  }
  else
  {
    ....
  } 
}


PVS-Studio警告V773引发异常,但未关闭'ffind'句柄引用的文件。资源泄漏是可能的。dir_nav_kernel_1.cpp 60



如果找到目录,则会引发异常。但是谁会关闭手柄?



第六个错误



另一个非常奇怪的地方。



inline double poly_min_extrap(double f0, double d0,
                              double x1, double f_x1,
                              double x2, double f_x2)
{
  ....
  matrix<double,2,2> m;
  matrix<double,2,1> v;

  const double aa2 = x2*x2;
  const double aa1 = x1*x1;
  m =  aa2,       -aa1,
      -aa2*x2, aa1*x1;   
  v = f_x1 - f0 - d0*x1,
      f_x2 - f0 - d0*x2;
  ....
}


PVS-Studio警告V521使用','运算符的此类表达式很危险。确保表达式正确。Optimization_line_search.h 211



计划初始化矩阵。但是,所有这些AA2f_x1D0等都是刚刚变量类型这意味着逗号不会分隔用于创建矩阵的参数,而是返回右侧值的普通逗号运算符



结论



在本文的开头,我举了一个示例,说明如何一次组合几个有用的东西。同时使用静态分析器也是有用的,这有几个原因:



  • 训练。通过研究分析仪警告,您可以学习很多新的有用的知识。示例:memset#pragma警告emplace_back严格对齐
  • 及早发现错别字,错误和潜在漏洞。
  • 代码逐渐变得更好,更简单,更易理解。
  • 您可以感到自豪,并在开发项目时告诉所有人您正在使用现代技术:)。这只是部分幽默。这是真正的竞争优势。


唯一的问题是如何启动,如何轻松实现它以及如何正确使用它?以下文章将帮助您:







如果您想与讲英语的人分享这篇文章,请使用翻译链接:Andrey Karpov。检查仅标头的C ++库集合(awesome-hpp)



All Articles