C++中按引用传递指针的原因?

7uzetpgm  于 2023-01-10  发布在  其他
关注(0)|答案(7)|浏览(192)

在什么情况下你会希望在c++中使用这种性质的代码呢?

void foo(type *&in) {...}

void fii() {
  type *choochoo;
  ...
  foo(choochoo);
}
5m1hhzi4

5m1hhzi41#

如果您需要修改指针而不是指针所指向的对象,则可能希望通过引用传递指针。
这类似于使用双指针的原因;使用对指针的引用比使用指针稍微安全一些。

rfbsl7qr

rfbsl7qr2#

50%的C++程序员喜欢在删除后将指针设置为null:

template<typename T>    
void moronic_delete(T*& p)
{
    delete p;
    p = nullptr;
}

如果没有引用,您将只更改指针的本地副本,而不会影响调用方。

fquxozlt

fquxozlt3#

大卫的回答是正确的,但如果说还有点抽象的话,这里有两个例子:
1.你可能想把所有释放的指针置零,以便更早地发现内存问题。

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

1.当处理链表时-通常简单地表示为指向下一个节点的指针:

struct Node
{
    value_t value;
    Node* next;
};

在这种情况下,当你插入到空列表时,你必须改变传入的指针,因为结果不再是NULL指针。这是一种你修改函数的外部指针的情况,这样它就在它的签名中有了指针的引用:

void insert(Node* &list)
{
    ...
    if(!list) list = new Node(...);
    ...
}

this question中有一个例子。

lztngnrs

lztngnrs4#

我不得不使用这样的代码来提供函数,以便为传入的指针分配内存并返回其大小,因为我的公司使用STL对我进行了“反对

int iSizeOfArray(int* &piArray) {
    piArray = new int[iNumberOfElements];
    ...
    return iNumberOfElements;
 }

这不是很好,但指针必须通过引用传递(或使用双指针)。如果不是,内存分配给指针的本地副本,如果它通过值传递,这会导致内存泄漏。

xuo3flqw

xuo3flqw5#

一个例子是当你写一个解析器函数并传递给它一个源指针来读取,如果函数应该把指针向前推到解析器正确识别的最后一个字符后面,那么使用一个指针的引用可以清楚地表明函数将移动原始指针来更新它的位置。
一般来说,如果你想把一个指针传递给一个函数,让它把原来的指针移动到其他位置,而不是只移动它的一个副本而不影响原来的指针,那么你就可以使用对指针的引用。

o4hqfura

o4hqfura6#

另一种情况是你有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)签名,您将拥有指针的副本,而不是原始指针。

68bkxrlz

68bkxrlz7#

参考以下代码:当我们将x作为Node *x传递时,将创建一个新变量,其地址与调用函数传递的地址相同。
1.如果修改指针所指向的值,该更改将反映在调用方函数变量中。
1.但是如果我们改变指针本身的值,它将不会反映在调用函数中,因为被调用函数拥有传递的指针的副本,而不是原始指针本身。

void increment(int *x) {
        (*x)++;
        x++;
        cout << x << endl;  // prints 0x7ffe9f8e1900
    }
    
    int main() {
        int a = 10;
        int *x = &a;
        increment(x);
        cout << *x << endl; // prints 11
        cout << x << endl;  // prints 0x7ffe9f8e18fc
        return 0;
    }

现在,检查下面的代码:当我们传递x作为Node *&x时,我们传递了一个在调用函数中出现的原始变量的引用,这意味着这两个变量(调用者和被调用者根)是相同的,它们的名称可能不同。
1.如果我们通过指针修改值指针,那么这个改变将反映在调用者函数变量中。
1.现在,如果我们改变指针本身的值,它也会反映在调用者函数变量中。

void increment(int* &x)
    {
        (*x) ++;
        cout << *x << endl; // prints 11
        x++;
        cout << x << endl;  // prints 0x7ffe9f8e1900
    }

    int main()
    {
        int a = 10;
        int *x = &a;
        increment(x);
        cout << *x << endl; // prints garbage
        cout << x << endl;  // prints 0x7ffcbeac5ea0
        return 0;
    }

相关问题