6

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

static inline void FreeAndNull(void*& item)

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

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

铸造它void*也不起作用

另外,有什么解决办法吗?

4

3 回答 3

9

答案是肯定的,您可以通过void*引用传递 a,而您得到的错误与此无关。问题是,如果你有一个通过引用获取的函数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!

由于指定的调用,上面的代码是非法的,并且有充分的理由。如果我们可以传入myIntArrayinto MyFunction,它将被重新分配以指向一个void*不是int数组类型的缓冲区。因此,从函数返回时,您int*将指向 type 数组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!

这是不合法的,因为如果您尝试将 a 传递给double一个采用 , 的函数int&,那么由于intdouble具有根本不同的二进制表示,您最终会double用无意义的数据破坏 the 的位。如果这个演员阵容是合法的,就有可能做这样的坏事。

所以简而言之,是的,你可以接受 a void* &,但如果你这样做,你必须通过真正void*的 s。正如 Erik 上面所指出的,如果您想释放指针模板并将其归零,那么您可以这样做。

如果你真的想将 auint_8*传入你的函数,你可以这样做:

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

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

希望这可以帮助!

于 2011-02-16T00:23:10.957 回答
6

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

试试这个:

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

编辑:修改示例以更好地反映 OP 的函数名称,并解决 @6502 完全正确的评论。

于 2011-02-16T00:19:53.923 回答
1

转换为 void* 不起作用的原因比其他地方解释的要简单得多:除非您明确指定引用,否则转换会创建右值。您不能将右值作为非常量引用传递。

证明给我看?试试这个:

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 而不是静态演员。

于 2011-02-16T00:36:20.747 回答