C++ 通过引用传递void*

C++ 通过引用传递void*,c++,function,pointers,reference,void-pointers,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*也不起作用 还有,有什么解决办法吗?如果通过引用获取voi

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

static inline void FreeAndNull(void*& item)
但是当我尝试调用它时,我得到以下错误:

Error   1   error C2664: 'FreeAndNull' : cannot convert parameter 1 from 'uint8_t *' to 'void *&'
将其强制转换为
void*
也不起作用


还有,有什么解决办法吗?

如果通过引用获取void*,则必须传递实际void*,而不是uint8\u t*

请尝试以下方法:

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

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

答案是肯定的,您可以通过引用传递一个
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*&
,但是如果你接受了,你必须通过real
void*
s。正如Erik在上面指出的那样,如果你想释放并归零一个指针模板就是一条路

如果您确实想将
uint\u 8*
传入函数,可以这样做:

uint_8* uPtr = /* ... */
void* ptr = uPtr;
FreeAndNull(ptr);
uPtr = (uint_8*) ptr;
这需要显式强制转换来告诉编译器“是的,我知道这可能不安全,但无论如何我都要这样做。”


希望这有帮助

对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),因为你实际上是在这里进行重新解释,而不是静态转换。

+1,酷!但现在我很好奇:为什么演员阵容在OP的例子中不起作用?在我看来,这是一个冒险的实现。我假设OP没有分配一个
uint8\t
元素,因此使用
delete
而不是
delete[]
是未定义的行为。@Cameron-请参阅下面我的答案,以了解演员阵容不起作用的原因。技术版本是在需要左值的地方生成右值,但直观的原因是它不安全。@template-没错,但您的答案甚至没有提到左值/右值。代码中存在此函数意味着您的代码可以改进。您不应该手动删除内容,也不应该关心指针的值。用智能指针代替。@GMan:好建议,但是为了这个问题+1的目的,情况被简化了,现在这很有意义。左值统治右值流口水@Cameron,templatetypedef:btw,用
(void*&)
铸造它会“起作用”(就像它会编译一样,我不确定以后使用它是否是UB)@Crazy Eddie-(我想你是否决了这个;如果没有,就忽略这个)你能解释一下这个答案的错误吗?我希望这是有用的,所以我能做的任何澄清都将不胜感激。请看我的回答和我对你评论的评论。“铸造创造右值”不一定是正确的
(void*&)x
产生一个左值。它看起来作为常量ref传递肯定不是OP想要的。@Fred-因为外表可能是欺骗的,我不明白你的意思。