2013-07-30 4 views
7

Я работаю над большой базой кода, преобразуя некоторые старые C-модули в C++. Я хочу добавить объект C++ в структуру, но некоторые пользователи этой структуры memset это, что является неудачным для объекта, который я хочу поместить в структуру.Предупреждение о времени компиляции о memset для несложенных старых данных

Как я могу обнаружить во время компиляции, что это делается, чтобы я мог устранить все использование memset на такой структуре, которая больше не является POD?

+0

Неужели 'grep'ing для' memset' слишком много результатов проверяет вручную? В противном случае я не вижу возможности для компилятора проверить это. – arne

+0

@arne Это часть проблемы, да. – Henrik

ответ

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_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 формирует эту ошибку:

error: no matching function for call to 'memset_if_pod_else_error'
memset(&np, 0, sizeof(np));
^~~~~~

Online Demo.

Надеюсь, что это поможет.

+0

Спасибо, это хорошая идея. Старый C-модуль также используется в тысячах мест для нового кода на C++, поэтому, к сожалению, для меня это частично разрешит мою проблему. – Henrik

+0

@ Хенрик: Я не вижу никаких проблем. Вы могли бы реализовать функцию соответственно. Смотрите мою демонстрацию. Надеюсь, что дает вашу идею * лучше. – Nawaz

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

Очевидно, что это может быть сделано «только на отладку строит».

+0

Если конструктор можно сделать 'constexpr', не может ли это также быть проверено статическим утверждением? – arne

+0

Проблема не в конструкции, проблема в том, что 'memset' на самом деле не заботится о том, что вы в нее впитываете, и просто прокладывайте прямо над всем, что вы им кормите, а это значит, что вам нужно проверить «волшебный» после (потенциальный вызов) 'memset'. –

2

Как об этом:

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); 
} 
+0

Тип возврата должен быть недействительным *, а не T *. – wolfgang

+0

Справедливая точка, спасибо. –

0

В этом случае isntead пытается найти все проблемные зоны , Я бы предложил просто предотвратить их в первую очередь. В частности, не добавляйте какие-либо возможности C++ к существующим C-структурам, а вместо этого пишите классы с соответствующим интерфекацией, которые содержат экземпляры структур данных C. Затем вы поддерживаете полную обратную совместимость со старыми структурами и кодом, а также добавляете новые возможности C++, которые вас интересуют.