C++ provides two primary mechanisms for indirectly accessing and modifying data:
- Pointers, which store memory addresses
- References, which act as aliases for existing variables
Though both can be used to access other variables, they serve different purposes, with distinct syntax, behavior, and safety characteristics.
What is a Pointer?
A pointer is a variable that holds the address of another variable.It enables indirect access and manipulation of data stored in a different memory location by referencing its address.
-
int* ptr
: Declares a pointer to anint
. It can store the address of an integer variable. -
&x
: The address-of operator (&
) is used to get the memory address of a variablex
.
Visualizing a pointer
Pointer Dereferencing
Dereferencing a pointer using (*
) gives access to the actual variable it points to, allowing you to read or modify it directly.
Null Pointers
Pointers can point to nothing, a null value
Pointer Arithematic
int* ptr = arr;
This means ptr
points to the first element of the array. In C++, the array name (arr
) automatically acts like a pointer to its first element.
Accessing Elements Using Pointer Arithmetic
-
*ptr
gives the value at the first element. -
*(ptr + 1)
moves the pointer one step ahead and accesses the second element. - You can keep doing
*(ptr + i)
to accessarr[i]
.
Accessing Class Members via Pointer
ptr->x
and ptr->show()
access members through the pointer using the ->
operator.
What is a Reference?
A reference is an alias for another variable. Once initialized, it cannot be changed to refer to another object.
- Always initialized during declaration
- No
nullptr
, no reassignment - Looks like a variable, behaves like an alias
- References are used to avoid copying of data, making the function more efficient, especially with large objects.
- They allow functions to modify the original variable directly.
- Pass-by-reference is useful when:
- You want to avoid performance overhead of copying.
- You need the function to update the caller's variable.
Passing by Reference Without Modification
Using const std::string&
means the function receives the original variable by reference, but promises not to modify it. This ensures safety while avoiding the overhead of copying.
When to Use Pointers
- Dynamic memory allocation
- Nullable objects
- Data structures (linked lists, trees)
- Interfacing with C libraries
- Arrays and pointer arithmetic
When to Use References
- Function arguments/return types
- Operator overloading
- Avoiding copies
- Cleaner syntax for indirection
Advanced Topics
Working with Pointers and Custom Classes in C++
In C++, when you create objects using new
, you get a pointer to that object. You must manually delete
it to free memory.
new
returns a pointer to the heap-allocated object.
You must call delete
to avoid memory leaks.
Returning by Reference
Allows function to return modifiable values:
Never return a reference to a local variable causes dangling reference.
Example (Dangling Reference):
-
x
is a local variable, so it gets destroyed whengetRef()
ends. - Returning a reference to it creates a dangling reference, leading to undefined behavior.
Pointers to Pointers
You can use a pointer to a pointer (int**
) to dynamically create and manage 2D arrays.
Smart Pointers (Modern C++)
Smart pointers are class templates in C++ that manage the lifetime of dynamically allocated objects. Unlike raw pointers (int*
), they automatically free memory when it's no longer needed, helping prevent:
- Memory leaks
- Dangling pointers
- Manual delete calls
They're part of the C++ Standard Library (since C++11) and live in the <memory>
header.
Types of Smart Pointers
std::unique_ptr
Owns a resource exclusively (no other pointer can point to it). Automatically deletes the object when it goes out of scope.
std::shared_ptr
Allows multiple pointers to share ownership of a dynamically allocated object. Internally uses reference counting.
std::weak_ptr
A non-owning smart pointer that observes a shared_ptr
without affecting its reference count. Prevents cyclic references.
A weak_ptr
does not own the object, so it can’t access it directly.To use the object safely, you use the .lock()
method.
.lock()
does two things:
- Checks if the object still exists (hasn't been deleted).
- Returns a
shared_ptr
to access the object only if it's still alive.
What is Reference Count in Smart Pointers?
Reference count is a number that keeps track of how many shared_ptrs
are pointing to the same object.
This count:
-
Increases when a
new
shared_ptr
is created from an existing one. -
Decreases when a
shared_ptr
is destroyed or reset.
When the reference count drops to zero, it means no one is using the object anymore, so it gets automatically deleted — no manual delete()
needed
Top comments (0)