Причина передачи указателя по ссылке в C++?


при каких обстоятельствах вы хотели бы использовать код такого рода в c++?

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

void fii() {
  type *choochoo;
  ...
  foo(choochoo);
}
6 76

6 ответов:

вы хотели бы передать указатель по ссылке, если у вас возникла необходимость изменить указатель, а не объект, на который указатель указывает.

Это похоже на то, почему используются двойные указатели; использование ссылки на указатель немного безопаснее, чем использование указателей.

50% программистов на C++ любят устанавливать свои указатели на null после удаления:

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

без ссылки, вы бы только меняя локальную копию указателя, не влияя на вызывающий.

ответ Дэвида правильный, но если он все еще немного абстрактен, вот два примера:

  1. вы можете обнулить все освобожденные указатели, чтобы поймать проблемы с памятью раньше. 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);
    
  2. при работе со связанными списками-часто просто представлены в виде указателей на следующий узел:

    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. Пример for_each в c++98.

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) подпись у вас есть копия указателя, а не оригинал.