关于非纯旧数据上的memset的编译时警告

Compile time warning about memset on non plain old data

本文关键字:memset 编译 警告 于非纯 数据      更新时间:2023-10-16

我正在处理一个大型代码库,将一些旧的C模块转换为C++。我想把一个C++对象添加到结构中,但这个结构的一些用户memset它,这对我想放在结构中的对象来说是不幸的。

我如何在编译时检测到这一点,以便在这样一个不再是POD的结构上消除memset的所有使用?

我不确定编译器是否会通过直接提供一些编译标志来帮助您。如果是,对你有好处。使用它。故事结束了。

如果没有,也许这会对你有所帮助。由于您正在将代码从C转换为C++,这意味着所有对memset的使用都没有std::命名空间。因此,利用这一事实和#define memset作为:

 #define memset memset_if_pod_else_error() 

这里memset_if_pod_else_error是您编写的函数(即您必须实现它)。您可以将其设置为模板,以便推断参数的类型,然后检测该类型是否为POD。如果是POD,那么这很好,并在内部调用std::memset,否则会引发错误。

std::enable_ifstd::is_pod这样的元函数将帮助您实现此函数。

以下是这个想法的最小演示:

#include <iostream>
#include <type_traits>
#include <cstring>
auto ptr_memset =  std::memset; //store this a pointer
template<typename T>
using VoidPtr = typename std::enable_if<std::is_pod<T>::value, void*>::type;
#define memset memset_if_pod_else_error
template<typename T>
VoidPtr<T> memset_if_pod_else_error(T *data, int ch, size_t count) 
{
      return ptr_memset(data, ch, count);
}
struct pod {};
struct nonpod { nonpod() {} };
int main()
{
    pod p;
    nonpod np;
    memset(&p, 0, sizeof(p));
    memset(&np, 0, sizeof(np));  //this is error!
}

memset的第二次调用生成以下错误:

错误:没有用于调用"memset_if_pod_else_error"的匹配函数
内存集(&np,0,sizeof(np))
^~~~~

在线演示。

希望能有所帮助。

这个怎么样:

auto orig_memset =  std::memset;
#define memset checked_memset
template <class T>
void* checked_memset(T* ptr, int value, size_t num) {
  static_assert(std::is_pod<T>::value, "memset on non-POD");
  return original_memset(data, value, num);
}

或者,如果您只对查找特定结构的违规行为感兴趣:

auto original_memset =  std::memset;
#define memset checked_memset
template <class T>
void* checked_memset(T* ptr, int value, size_t num) {
  static_assert(!std::is_same<T, YOUR_STRUCT_HERE>::value, "memset used on YOUR_STRUCT_HERE");
  return original_memset(data, value, num);
}

我认为您无法在编译时检测到在非POD数据上使用memset

您可以添加一个额外的字段,该字段在构造函数中设置,然后签入任何其他成员函数。类似这样的东西:

 class X
 {
    const int MAGIC = 123456789;
    int magic;
    ...
  public:
    X() : magic(MAGIC) { ... }
    ... 
    void do_stuff()
    {
       check_magic();
       ... 
    } 
  private: 
    void check_magic() 
    { 
      if (magic != MAGIC) { ... do something to indicate bad state ... }; 
    }
 }; 

显然,这可以"仅在调试构建时"完成。

在这种情况下,我建议不要试图找到所有的问题领域,而是从一开始就预防它们。具体来说,不要在现有的C结构中添加任何C++功能,而是使用包含C数据结构实例的适当接口编写类。然后,您可以保持与旧结构和代码的完全向后兼容性,并添加您感兴趣的新C++功能。