8

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

如何在编译时检测到这正在完成,以便我可以消除memset对不再是 POD 的这种结构的所有使用?

4

4 回答 4

8

我不确定编译器是否会通过直接提供一些编译标志来帮助你。如果是这样,对你有好处。用那个。故事结局。

如果没有,那么也许这会对您有所帮助。由于您将代码从 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'
memset(&np, 0, sizeof(np));
^~~~~~

在线演示

希望有帮助。

于 2013-07-30T12:07:09.373 回答
3

这个怎么样:

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);
}
于 2013-07-30T12:22:34.257 回答
1

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

您可以做的是添加一些在构造函数中设置的额外字段,然后检查任何其他成员函数。像这样的东西:

 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 ... }; 
    }
 }; 

显然,这可以“仅在调试版本上”完成。

于 2013-07-30T12:07:46.037 回答
0

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

于 2013-07-30T13:12:41.490 回答