2

how to choose value or pointer or reference?

when I code in c++, I don't have a clean idea when to choose each one?

Is there one priority or rule when choosing?

greedybuddha
  • 7,488
  • 3
  • 36
  • 50
jiafu
  • 6,338
  • 12
  • 49
  • 73
  • References have nicer syntax, but some people prefer how callers have to be explicit with pointers, and there are differences in the semantics (see [here](http://stackoverflow.com/questions/57483/what-are-the-differences-between-pointer-variable-and-reference-variable-in-c?rq=1)). – chris May 16 '13 at 01:06
  • I agree with chris. I usually try to use references when possible. It looks a bit cleaner to me, usually a bit easier to debug as well. – greedybuddha May 16 '13 at 01:09
  • IMHO, you should limit your use of pointers in "storing" heap objects. For any other uses, use references. – Mark Garcia May 16 '13 at 01:11
  • @MarkGarcia, But there's RAII for that :) (It uses pointers internally, though). – chris May 16 '13 at 01:14
  • @chris It's implied. ;) – Mark Garcia May 16 '13 at 01:14
  • And also, pointers and references have their respective semantics and you should then use them only when the situation calls you to do so and when it's appropriate. – Mark Garcia May 16 '13 at 01:16

3 Answers3

6

You use a value when

  • Your data member is principal, i.e. not a copy of something else or a reference to another value
  • You would like an independent copy that you would like to modify
  • The object is much smaller than the pointer/reference, and you need many of them

You use pointers or references when

  • The object is too large to copy efficiently
  • The object needs to be modifiable in some other part of the code

You decide between a pointer and a reference using a simple rule: if there are situations where your referenced object does not exist, or the same variable must refer to different objects throughout its lifetime, use a pointer; otherwise, use a reference.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Do you think `std::optional` will replace your argument (at least an empty return) for using pointers come widespread C++14? – chris May 16 '13 at 01:18
  • @chris I think `optional` is a bit different - it's similar to nullable value types of .NET. No doubt, the introduction of `optional` will displace some of the uses of pointers, but many more uses would remain. – Sergey Kalinichenko May 16 '13 at 01:24
  • Agreed. Admittedly, I don't use nullable types that often, but that might be because I don't use C# all that often yet. – chris May 16 '13 at 01:35
  • @dasblinkenlight One of the main ones being calling interfaces of language agnostic or C APIs. – Anthony May 16 '13 at 01:35
1

I'll try, just for others to correct me:

If it really can't be null, and you don't want to store it, and it's not primitive, use reference; If you don't need to change it, use const reference.

Otherwise, if you need to change it, or to store it, use pointer (better: smart pointers). If it's not primitive, use const pointer.

If you need runtime polymorphism, you must not use pass-by-value.

Otherwise, use pass by value. use int and not const int&.

If you are writing a template, remember that passing by value (or copying in any way) implies a working copy-constructor as a constraint on the type. references might work wierd if the type is an array (or a string-literal).

Elazar
  • 20,415
  • 4
  • 46
  • 67
  • +1: Your advice pretty much corresponds with my practice. The Q&A at [C++: null reference](http://stackoverflow.com/questions/4364536/c-null-reference) is insightful on your first point. – Simon May 16 '13 at 01:19
0

I'll give a small round-up of what I think is good practise concerning the selection of a type derived from arbitary T.

template <typename _T>
void CALLED (_T B) { /* _STUFF_ */ }

template <typename T>
void CALLER (void)
{
  T A;
  typedef T TYPE;
  CALLED<TYPE>(A);
}

TYPE can be one of the following:

  • T (value type),
  • T& (reference),
  • T const & (reference to const T),
  • T* (pointer),
  • T const * (pointer to const T),
  • T const * const (const pointer to const T),
  • T * const (const pointer to non-const T)

Note: For the pointer types the call statement would change to CALLED<TYPE>(&A);.

If CALLED() is intended to have a valid object

This should imho be somehow "default".

Guarantee to conserve A(^) |    no    |   yes   |     yes     |   yes   |
Alteration of B desired    |    yes   |   yes   |     no      |    no   |
sizeof(T) > sizeof(T*)     |  yes/no  |  yes/no |     yes     |    no   |
-------------------------------------------------------------------------
TYPE (of B)                |    T&    |    T    |  T const &  | T const |

(^): A "no" in this row can also mean that you want to alter A on purpose. I'll just have the optimal type depicted that conservation of A is guaranteed if this is not the case.

If CALLED() can (and does) depict whether it gets a valid object

Since it is not very smart to bind a references to NULL and since a value parameter will always try to obtain an object, we'll have to stick to pointers here. Since call by value does not make much sense here, size of T is irrelevant.

Guarantee to conserve A(=*B) |    no    |       yes       |     yes     |    no   |
Alteration of B              |    no    |        no       |     yes     |   yes   |
-----------------------------------------------------------------------------------
TYPE                         | T* const | T const * const |  T const *  |    T*   |
Pixelchemist
  • 24,090
  • 7
  • 47
  • 71