109

Under which circumstances would you want to use code of this nature in c++?

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

void fii() {
  type *choochoo;
  ...
  foo(choochoo);
}
Matthew Hoggan
  • 6,723
  • 13
  • 63
  • 120

6 Answers6

160

You would want to pass a pointer by reference if you have a need to modify the pointer rather than the object that the pointer is pointing to.

This is similar to why double pointers are used; using a reference to a pointer is slightly safer than using pointers.

Ziezi
  • 6,049
  • 3
  • 34
  • 45
David Z.
  • 5,363
  • 2
  • 18
  • 13
  • 14
    So similar to a pointer of a pointer, except one less level of indirection for pass-by-reference semantics? –  Apr 20 '12 at 04:15
  • I'd like to add that sometimes you also want to return a pointer by reference. For instance, if you have a class holding data in a dynamically allocated array, but you want to provide (nonconstant) access to this data to the client. At the same time, you do not want the client to be able to manipulate the memory through the pointer. –  May 16 '16 at 00:50
  • 2
    @William can you elaborate on that? It sounds interesting. Does it mean that the user of that class could get a pointer to the internal data buffer and read/write to it, but it cannot – for example – free that buffer using `delete` or rebind that pointer to some other place in memory? Or did I get it wrong? – BarbaraKwarc Aug 04 '16 at 01:09
  • 2
    @BarbaraKwarc Sure. Say you have a simple implementation of a dynamic array. Naturally you'll overload the `[]` operator. One possible (and in fact natural) signature for this would be `const T &operator[](size_t index) const`. But you could also have `T &operator[](size_t index)`. You could have both at the same time. The latter would let you do things like `myArray[jj] = 42`. At the same time, you aren't providing a pointer to your data, so the caller cannot mess with the memory (e.g. delete it accidentally). –  Sep 19 '16 at 02:03
  • Oh. I thought you were talking about returning a reference to a pointer (your exact wording: "return a pointer by reference", because that was what OP was asking about: passing pointers by references, not just plain old references) as some fancy way of giving read/write access to the buffer without allowing to manipulate the buffer itself (e.g. freeing it). Returning a plain old reference is a different thing and I know that. – BarbaraKwarc Sep 26 '16 at 10:37
  • @DavidZ. `...if you need to modify the pointer` *rather than* `the object...` Do you mean to say this should only be used to modify the pointer, and should not be used to modify the object being pointed to? – Yankee Nov 07 '17 at 22:56
68

50% of C++ programmers like to set their pointers to null after a delete:

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

Without the reference, you would only be changing a local copy of the pointer, not affecting the caller.

Puppy
  • 138,897
  • 33
  • 232
  • 446
fredoverflow
  • 237,063
  • 85
  • 359
  • 638
  • 3
    I will trade sounding stupid for figuring out the answer: why is it called moronic delete? What am I missing? – Sammaron Sep 06 '15 at 17:26
  • 2
    @Sammaron If you look at the history, the function template used to be called `paranoid_delete`, but Puppy renamed it to `moronic_delete`. He probably belongs to the other 50% ;) Anyway, the short answer is that settings pointers to null after `delete` is almost never useful (because they should go out of scope, anyway) and often hampers the detection of "use after free" bugs. – fredoverflow Sep 07 '15 at 18:19
  • @fredoverflow I understand your response, but @Puppy seems to think `delete` is stupid in general. Puppy, I did some googling, I can't see why delete is completely useless (maybe I'm a terrible googler too ;)). Can you explain a little more or provide a link? – Sammaron Sep 07 '15 at 20:18
  • @Sammaron, C++ has "smart pointers" now that encapsulate regular pointers and automatically call "delete" for you when they go out of scope. Smart pointers are vastly preferred over C-style dumb pointers because they eliminate this problem entirely. – tjwrona1992 Nov 28 '19 at 02:19
15

David's answer is correct, but if it's still a little abstract, here are two examples:

  1. You might want to zero all freed pointers to catch memory problems earlier. C-style you'd do:

    void freeAndZero(void** ptr)
    {
        free(*ptr);
        *ptr = 0;
    }
    
    void* ptr = malloc(...);
    
    ...
    
    freeAndZero(&ptr);
    

    In C++ to do the same, you might do:

    template<class T> void freeAndZero(T* &ptr)
    {
        delete ptr;
        ptr = 0;
    }
    
    int* ptr = new int;
    
    ...
    
    freeAndZero(ptr);
    
  2. When dealing with linked-lists - often simply represented as pointers to a next node:

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

    In this case, when you insert to the empty list you necessarily must change the incoming pointer because the result is not the NULL pointer anymore. This is a case where you modify an external pointer from a function, so it would have a reference to pointer in its signature:

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

There's an example in this question.

Community
  • 1
  • 1
Antoine
  • 11,369
  • 6
  • 33
  • 47
9

I have had to use code like this to provide functions to allocate memory to a pointer passed in and return its size because my company "object" to me using the STL

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

It is not nice, but the pointer must be passed by reference (or use double pointer). If not, memory is allocated to a local copy of the pointer if it is passed by value which results in a memory leak.

mathematician1975
  • 20,311
  • 6
  • 52
  • 93
2

One example is when you write a parser function and pass it a source pointer to read from, if the function is supposed to push that pointer forward behind the last character which has been correctly recognized by the parser. Using a reference to a pointer makes it clear then that the function will move the original pointer to update its position.

In general, you use references to pointers if you want to pass a pointer to a function and let it move that original pointer to some other position instead of just moving a copy of it without affecting the original.

BarbaraKwarc
  • 2,511
  • 2
  • 10
  • 17
0

Another situation when you may need this is if you have stl collection of pointers and want to change them using stl algorithm. Example of for_each in 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();
  } 

};

Otherwise, if you use changeObject(Object* item) signature you have copy of pointer, not original one.

Nine
  • 15
  • 5