在什么情况下你想在 c++ 中使用这种性质的代码?
void foo(type *&in) {...}
void fii() {
type *choochoo;
...
foo(choochoo);
}
如果您需要修改指针而不是指针指向的对象,您可能希望通过引用传递指针。
这类似于为什么使用双指针;使用对指针的引用比使用指针稍微安全一些。
50% 的 C++ 程序员喜欢在删除后将指针设置为 null:
template<typename T>
void moronic_delete(T*& p)
{
delete p;
p = nullptr;
}
如果没有引用,您只会更改指针的本地副本,而不会影响调用者。
大卫的回答是正确的,但如果还是有点抽象,这里举两个例子:
您可能希望将所有已释放的指针归零以更早地发现内存问题。你会做的C风格:
void freeAndZero(void** ptr)
{
free(*ptr);
*ptr = 0;
}
void* ptr = malloc(...);
...
freeAndZero(&ptr);
在 C++ 中做同样的事情,你可以这样做:
template<class T> void freeAndZero(T* &ptr)
{
delete ptr;
ptr = 0;
}
int* ptr = new int;
...
freeAndZero(ptr);
在处理链表时——通常简单地表示为指向下一个节点的指针:
struct Node
{
value_t value;
Node* next;
};
在这种情况下,当您插入空列表时,您必须更改传入指针,因为结果不再是NULL
指针。这是您从函数修改外部指针的情况,因此它将在其签名中引用指针:
void insert(Node* &list)
{
...
if(!list) list = new Node(...);
...
}
这个问题有一个例子。
我不得不使用这样的代码来提供函数来为传入的指针分配内存并返回其大小,因为我的公司使用 STL 对我“对象”
int iSizeOfArray(int* &piArray) {
piArray = new int[iNumberOfElements];
...
return iNumberOfElements;
}
这不好,但指针必须通过引用传递(或使用双指针)。如果不是,则内存分配给指针的本地副本,如果它是按值传递的,这会导致内存泄漏。
一个例子是,当您编写一个解析器函数并将一个源指针传递给它以从中读取时,如果该函数应该将该指针向前推到解析器正确识别的最后一个字符之后。使用对指针的引用可以清楚地表明该函数将移动原始指针以更新其位置。
通常,如果您想将指针传递给函数并让它将原始指针移动到其他位置而不是仅移动它的副本而不影响原始指针,则使用对指针的引用。
您可能需要这样做的另一种情况是,如果您有 stl 指针集合并希望使用 stl 算法更改它们。c++98 中的 for_each 示例。
struct Storage {
typedef std::list<Object*> ObjectList;
ObjectList objects;
void change() {
typedef void (*ChangeFunctionType)(Object*&);
std::for_each<ObjectList::iterator, ChangeFunctionType>
(objects.begin(), objects.end(), &Storage::changeObject);
}
static void changeObject(Object*& item) {
delete item;
item = 0;
if (someCondition) item = new Object();
}
};
否则,如果您使用changeObject(Object* item)签名,则您有指针的副本,而不是原始的。