A pointer can be re-assigned:
int x = 5;
int y = 6;
int *p;
p = &x;
p = &y;
*p = 10;
assert(x == 5);
assert(y == 10);
A reference cannot be re-bound, and must be bound at initialization:
int x = 5;
int y = 6;
int &q; // error
int &r = x;
A pointer variable has its own identity: a distinct, visible memory address that can be taken with the unary &
operator and a certain amount of space that can be measured with the sizeof
operator. Using those operators on a reference returns a value corresponding to whatever the reference is bound to; the reference’s own address and size are invisible. Since the reference assumes the identity of the original variable in this way, it is convenient to think of a reference as another name for the same variable.
int x = 0;
int &r = x;
int *p = &x;
int *p2 = &r;
assert(p == p2); // &x == &r
assert(&p != &p2);
You can have arbitrarily nested pointers to pointers offering extra levels of indirection. References only offer one level of indirection.
int x = 0;
int y = 0;
int *p = &x;
int *q = &y;
int **pp = &p;
**pp = 2;
pp = &q; // *pp is now q
**pp = 4;
assert(y == 4);
assert(x == 2);
A pointer can be assigned nullptr
, whereas a reference must be bound to an existing object. If you try hard enough, you can bind a reference to nullptr
, but this is undefined and will not behave consistently.
/* the code below is undefined; your compiler may optimise it
* differently, emit warnings, or outright refuse to compile it */
int &r = *static_cast<int *>(nullptr);
// prints "null" under GCC 10
std::cout
<< (&r != nullptr
? "not null" : "null")
<< std::endl;
bool f(int &r) { return &r != nullptr; }
// prints "not null" under GCC 10
std::cout
<< (f(*static_cast<int *>(nullptr))
? "not null" : "null")
<< std::endl;
You can, however, have a reference to a pointer whose value is nullptr
.
Pointers can iterate over an array; you can use ++
to go to the next item that a pointer is pointing to, and + 4
to go to the 5th element. This is no matter what size the object is that the pointer points to.
A pointer needs to be dereferenced with *
to access the memory location it points to, whereas a reference can be used directly. A pointer to a class/struct uses ->
to access its members whereas a reference uses a .
.
References cannot be put into an array, whereas pointers can be (Mentioned by user @litb)
Const references can be bound to temporaries. Pointers cannot (not without some indirection):
const int &x = int(12); // legal C++
int *y = &int(12); // illegal to take the address of a temporary.
This makes const &
more convenient to use in argument lists and so forth.
Best Answer
No, C++ does not support 'finally' blocks. The reason is that C++ instead supports RAII: "Resource Acquisition Is Initialization" -- a poor name† for a really useful concept.
The idea is that an object's destructor is responsible for freeing resources. When the object has automatic storage duration, the object's destructor will be called when the block in which it was created exits -- even when that block is exited in the presence of an exception. Here is Bjarne Stroustrup's explanation of the topic.
A common use for RAII is locking a mutex:
RAII also simplifies using objects as members of other classes. When the owning class' is destructed, the resource managed by the RAII class gets released because the destructor for the RAII-managed class gets called as a result. This means that when you use RAII for all members in a class that manage resources, you can get away with using a very simple, maybe even the default, destructor for the owner class since it doesn't need to manually manage its member resource lifetimes. (Thanks to Mike B for pointing this out.)
For those familliar with C# or VB.NET, you may recognize that RAII is similar to .NET deterministic destruction using IDisposable and 'using' statements. Indeed, the two methods are very similar. The main difference is that RAII will deterministically release any type of resource -- including memory. When implementing IDisposable in .NET (even the .NET language C++/CLI), resources will be deterministically released except for memory. In .NET, memory is not deterministically released; memory is only released during garbage collection cycles.
† Some people believe that "Destruction is Resource Relinquishment" is a more accurate name for the RAII idiom.