我正在开发一个大型代码库,将一些旧的 C 模块转换为 C++。我想将一个 C++ 对象添加到一个结构中,但是这个结构的一些用户使用memset
它,这对于我想要放入结构中的对象来说是不幸的。
如何在编译时检测到这正在完成,以便我可以消除memset
对不再是 POD 的这种结构的所有使用?
我正在开发一个大型代码库,将一些旧的 C 模块转换为 C++。我想将一个 C++ 对象添加到一个结构中,但是这个结构的一些用户使用memset
它,这对于我想要放入结构中的对象来说是不幸的。
如何在编译时检测到这正在完成,以便我可以消除memset
对不再是 POD 的这种结构的所有使用?
我不确定编译器是否会通过直接提供一些编译标志来帮助你。如果是这样,对你有好处。用那个。故事结局。
如果没有,那么也许这会对您有所帮助。由于您将代码从 C 转换为 C++,这意味着 memset 的所有使用都没有std::
命名空间。因此,利用这一事实并#define memset
作为:
#define memset memset_if_pod_else_error()
这memset_if_pod_else_error
是您编写的函数(即您必须实现它)。您可以将其设为模板以推断参数的类型,然后检测类型是否为 POD。如果是 POD,那很好并在std::memset
内部调用,否则会引发错误。
元函数std::enable_if
和std::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));
^~~~~~
在线演示。
希望有帮助。
这个怎么样:
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);
}
我认为您无法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 ... };
}
};
显然,这可以“仅在调试版本上”完成。
在这种情况下,不是试图找到所有问题区域,我建议首先阻止它们。具体来说,不要向现有的 C 结构添加任何 C++ 功能,而是使用包含 C 数据结构实例的适当接口编写类。然后,您保持与旧结构和代码的完全向后兼容性,并添加您感兴趣的新 C++ 功能。