2010-06-26 2 views
1

Мне нужно создать функцию, которая может принимать в массиве указателей с известным размером и установить все указатели в NULL. Осторожность в том, что я не знаю тип заранее. Это то, что я пытался до сих пор:Очистить массив до NULL, не зная тип

template <typename T> 
    static void Nullify(T** _Array, int _Size, unsigned int _SizeOf) 
    { 
    for (int i = 0; i < _Size; i++) 
    { 
    _Array[i * _SizeOf] = NULL; 
    } 
    } 

Что дает мне ошибки (не сама функция, но я попирая память не должна быть попирая в результате ошибки памяти позже). Я передаю массив (_Array - уже инициализирован _Size), его размер (_Size) и sizeof (Pointer *) как _SizeOf.

Любая помощь будет принята с благодарностью :)

+7

Кстати, имена параметров недействительны. Имена, начинающиеся с '_', за которым следует буква верхнего регистра, зарезервированы. –

+0

+1 для указания зарезервированных имен. – stinky472

+0

Ничего себе, спасибо! Не имел представления. Мне придется изменить свое соглашение. – Samaursa

ответ

7

Вам не нужно _SizeOf. Это то, что вы хотите:

template <typename T> 
static void Nullify(T** _Array, int _Size) 
{ 
    for (int i = 0; i < _Size; i++) 
    { 
     _Array[i] = NULL; 
    } 
} 

Компилятор знает размер указателя, и делает математику для вас во время разыменования массива.

+0

А как насчет 'T ** _Array'? Почему указатель на указатель? – Wizard79

+0

Каждый массив представлен как указатель на его первый элемент. T ** означает массив указателей - он указывает на первый указатель в массиве – ognian

+0

Спасибо!Я неправильно предполагал, что компилятор не будет знать, какой тип был передан. – Samaursa

1

Вы не должны делать _Array[i * _SizeOf] = NULL, а скорее _Array[i] = NULL.

1

Я согласен с ответом Рида, конечно же, вы также должны удалить '* _SizeOf' в своем задании.

Если возможно, я также предлагаю вам отойти от «сырых» массивов и использовать в вашем коде std :: vector. Это более безопасная структура с массивной семантикой и накладывает лишь небольшие накладные расходы.

+0

В этом случае у меня не было выбора, иначе я бы определенно пошел с контейнерами – Samaursa

0

Вы не должны полагаться на значение _SizeOf вашего значения, чтобы узнать его тип, вы должны использовать функцию, чтобы определить ее тип.

В какой момент вы объявляете свой T** _Array? Возможно, здесь вы должны убедиться, что ваш метод гарантирует определенный тип Array для любой части вашей программы, которая его называет, не так ли?

3
template <class T> 
void Nullify(T** the_array, unsigned int size) 
{ 
    std::fill(the_array, the_array + size, static_cast<T*>(0)); 
} 

template <class T, unsigned int N> 
void Nullify(T* (&the_array)[N]) 
{ 
    Nullify(the_array, N); 
} 

Вторая позволяет передавать массив указателей и сворачивать их, даже не передавая аргумент размера. Это требует, чтобы у вас есть реальный массив, чтобы пройти в, а не указатель:

Foo* x[10] = {...} 
Nullify(x); // sets all pointers in x to 0 (NULL) 

... или если вы просто хотите написать его самостоятельно в цикле (это, как правило, не будет столь же быстро, как станд :: заполнить который может даже сделать фактическое заполнение через очень эффективный код сборки для стручки):

template <class T> 
void Nullify(T** the_array, unsigned int size) 
{ 
    for (unsigned int j=0; j < size; ++j) 
     the_array[j] = 0; 
} 

Обратите внимание, что я также не использовать NULL по той же причине Страуструп делает это (исключает необходимость включения cstddef). Когда C++ 0x будет более широко внедряться, ключевое слово nullptr сделает приятную замену.

BTW: ключевое слово static игнорируется для шаблонов функций. У них уже есть внутренняя связь, поэтому лишний добавить ее.

+1

+1 для предложения 'std :: fill' или простого цикла; -1 для предложения 'memset'. См. Комментарии к http://stackoverflow.com/questions/3124990/clear-an-array-to-null-without-knowing-the-type/3125002#3125002 –

+0

@Mike (вставлено) Это слишком педантично. Предположим, что конструкция указателя особых случаев компилятора, такая, что 0 преобразуется в адрес, 0xFFFFFFFF. Покажите мне один компилятор, который сделает что-нибудь подобное. Их не будет. В течение многих лет, полагаясь на вектор, который должен быть смежным, вызывал неопределенное поведение (без смежных гарантий), но любой здравомыслящий знал бы, что нет другого разумного способа реализации std :: vector. Попросите любого программиста на C такой же вопрос здесь, и они ответят с помощью memset. Не имеет значения, используют ли они NULL для второго аргумента, потому что memset принимает int для val! – stinky472

+0

[снова вставлено, извинения, но @see оригинальное обсуждение] Фактически, в «переносной» стандартной библиотечной реализации Dinkumware даже используется memset для std :: fill с POD. Это слишком широко используется в соглашении (по крайней мере, в ANSI C) для реализации адресов указателей NULL как ничего, кроме 0. Это похоже на то, что вызов, вызывающий побитовое сравнение кода, не переносится, поскольку код предполагает, что байт имеет 8 бит. Тем не менее, это, по крайней мере, более разумный аргумент, учитывая, что существуют * существующие машины, где это не так. – stinky472