通过引用传递空白*

时间:2011-02-16 00:16:19

标签: c++ function pointers reference void-pointers

为什么我不能通过引用传递void*?编译器允许我使用以下签名声明一个函数:

static inline void FreeAndNull(void*& item)

但是当我尝试调用它时,我收到以下错误:

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

将其投放到void*无效

另外,有没有解决方法?

3 个答案:

答案 0 :(得分:8)

答案是肯定的,您可以通过引用传递void*,而您获得的错误与此无关。问题是如果你有一个通过引用获取void*的函数,那么你只能传入实际为void*的变量作为参数。这是有充分理由的。例如,假设您有此功能:

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&的函数,那么intdouble具有根本不同的二进制表示形式,你最终会用无意义的数据来破坏double的各个部分。如果这个演员是合法的,就有可能做这样的坏事。

所以简而言之,是的,你可以接受void* &,但如果你这样做,你必须传入真正的void*。正如Erik上面指出的那样,如果你想要释放零指针模板,那么就可以了。

如果你确实想要将uint_8*传递给你的函数,你可以这样做:

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

这需要显式转换告诉编译器“是的,我知道这可能不安全,但无论如何我都会这样做。”

希望这有帮助!

答案 1 :(得分:6)

如果您通过引用获取void *,则必须传递实际的void *,而不是uint8_t *。

请改为尝试:

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

编辑:修改样本以更好地反映OP的功能名称,并解决@ 6502完全正确的评论。

答案 2 :(得分:1)

转换为void *不起作用的原因比在别处解释的简单得多:除非您明确指定引用,否则转换会创建rvalues。您不能将rvalue作为非const引用传递。

证明吗?试试这个:

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

我敢打赌,这将是非常糟糕的事情(tm),因为你实际上是在这里进行reinterpret_cast而不是静态演员。