Передача пустоты * по ссылке - PullRequest
5 голосов
/ 16 февраля 2011

Почему я не могу передать void* по ссылке?Компилятор позволяет мне объявить функцию со следующей подписью:

static inline void FreeAndNull(void*& item)

Но когда я пытаюсь вызвать ее, я получаю следующую ошибку:

Error   1   error C2664: 'FreeAndNull' : cannot convert parameter 1 from 'uint8_t *' to 'void *&'

Приведение к void* тоже не работает

Кроме того, есть ли обходные пути?

Ответы [ 3 ]

8 голосов
/ 16 февраля 2011

Ответ - да, вы можете передать void* по ссылке, и ошибка, которую вы получаете, не связана с этим.Проблема в том, что если у вас есть функция, которая принимает void* по ссылке, то вы можете передать только переменные, которые на самом деле void* s в качестве параметра.Для этого есть веская причина.Например, предположим, что у вас есть эта функция:

void MyFunction(void*& ptr) {
    ptr = malloc(137); // Get a block of raw memory
}

int* myIntArray;
MyFunction(myIntArray); // Error- this isn't legal!

Приведенный выше код недопустим из-за указанного вызова и по уважительной причине.Если бы мы могли передать myIntArray в MyFunction, он был бы переназначен для указания на буфер типа void*, который не является массивом int.Следовательно, при возврате из функции ваш int* будет указывать на массив типа void*, подрывая систему типов.Это не означает, что C ++ имеет сильную систему типов - это не так - но если вы собираетесь подорвать ее, вы должны явно добавить некоторые приведения.

Вы также не можете сделать это:

void MyFunction(void*& ptr) {
    ptr = malloc(137); // Get a block of raw memory
}

int* myIntArray;
MyFunction((void*)myIntArray); // Error- this isn't legal!

В качестве хорошей справки о том, почему вы не можете сделать это, подумайте об этом коде:

void OtherFunction(int& myInt) {
    myInt = 137;
}

double myDouble;
OtherFunction((int)myDouble); // Also error!

Это недопустимо, потому что если вы попытались передатьdouble в функцию, которая заняла int&, тогда, поскольку int и double имеют принципиально разные двоичные представления, вы в конечном итоге забьете биты double бессмысленными данными.Если бы этот бросок был законным, было бы возможно делать плохие вещи, как это.

Короче говоря, да, вы можете взять void* &, но если вы это сделаете, вы должны пройти в реальномvoid* s.Как указывал Эрик выше, если вы хотите освободить и обнулить шаблоны указателей, вам стоит пойти по этому пути.

Если вы действительно хотите передать uint_8* в эту вашу функцию, вы можете сделать так:это:

uint_8* uPtr = /* ... */
void* ptr = uPtr;
FreeAndNull(ptr);
uPtr = (uint_8*) ptr;

Это требует явного приведения, чтобы сказать компилятору: «Да, я знаю, что это может быть небезопасно, но я все равно это сделаю».

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

6 голосов
/ 16 февраля 2011

Если вы берете void * по ссылке, вы должны передать фактический void *, а не uint8_t *.

Попробуйте вместо этого:

template<typename T> inline void FreeAndNull(T * & V) { free(V); V = 0; }

РЕДАКТИРОВАТЬ: Модифицированный образец, чтобы лучше отражать имя функции OP, а также адресовать полностью правильный комментарий @ 6502.

1 голос
/ 16 февраля 2011

Преобразование в пустоту * не работает по причине, намного более простой, чем объясняется в другом месте: приведение создает значения r, если вы явно не указали ссылку.Вы не можете передать rvalue как неконстантную ссылку.

Докажите это?Попробуйте это:

void fun(void * &) {}
int main() { int * x; void * x2 = x; fun(x); }

Если это подходит для использования, попробуйте это:

void fun(void * const&);

Теперь не только кастинг работает, это неявное.

Приведение к ссылкеможет быть опаснымЭто на самом деле вызывает компиляцию вашего кода, но я не буду говорить о его поведении:

void fun(void *&){}
int main() { int * x; fun((void*&)x); }

Моя ставка в том, что это будет очень плохо (тм), так как вы на самом деле делаете reinterpret_castздесь, а не статическое приведение.

...