I'm working on a large code base, converting some old C modules into C++. I want to add a C++ object to a struct, but some users of this struct memset
it, which is unfortunate for the object that I want to put in the struct.
How can I detect at compile time that this is being done, so that I can eliminate all use of memset
on such a struct that is no longer POD?
I'm not sure if compiler will help you there by directly providing some compilation flags. If it does, good for you. Use that. End of story.
If it doesn't, then maybe this will help you. Since you're converting your code from C to C++, that means all the usage of memset is without std::
namespace. So take advantage of this fact and #define memset
as:
#define memset memset_if_pod_else_error()
Here memset_if_pod_else_error
is a function written by you (i.e you have to implement it). You could make it template so as to deduce the type of argument and then detect whether the type is POD or not. If it is POD, then that is fine and call std::memset
internally, else raise error.
Metafunctions like std::enable_if
and std::is_pod
will help you to implement this function.
Here is a minimal demo of this idea:
#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!
}
The second call to memset
generates this error:
error: no matching function for call to 'memset_if_pod_else_error'
memset(&np, 0, sizeof(np));
^~~~~~
Online Demo.
Hope that helps.
How about this:
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);
}
Or, if you're interested only in finding violations for your particular struct:
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With