Functions
Function Parameters
Pass by value, reference, and pointer
Interview: Critical for interviews
Function Parameters
Choosing the right parameter passing strategy is critical for correctness and performance. Each strategy has different semantics for ownership, mutability, and copy overhead.
| Strategy | Syntax | Copies? | Modifies Original? | Use When |
|---|---|---|---|---|
| By Value | void f(T x) | Yes | No | Small/cheap types, need local copy |
| By Reference | void f(T& x) | No | Yes | Must modify caller's object |
| By Const Ref | void f(const T& x) | No | No | Large objects, read-only |
| By Pointer | void f(T x) | No | Yes (via deref) | Optional param (can be nullptr) |
| By Rvalue Ref | void f(T&& x) | No | Yes (moves) | Move semantics/perfect forwarding |
Interview Corner
Q: When should you pass by value versus const reference?
A: Pass by value for cheap-to-copy types (ints, pointers, std::string_view) or when you need a local copy anyway. Pass by const reference for expensive-to-copy types (std::vector, std::string, large structs). The guideline: if sizeof(T) <= 2sizeof(void*), pass by value; otherwise, by const reference.
Q: What is the "sink" parameter pattern?
A: When a function needs to store a parameter (e.g., in a constructor), taking it by value and then moving it is the modern idiom: void setName(std::string name) { m_name = std::move(name); }. This allows the compiler to elide copies when called with temporaries (rvalues) while one copy when called with lvalues.
Common Pitfalls
- Passing large objects by value in hot loops: Each call copies the entire object, dramatically reducing performance.
- Returning reference to parameter passed by value: The parameter is a local copy that is destroyed on return.
Best Practices
- Default to
const T&for non-trivial types, andTby value for cheap types (int, char, float, pointers). - Use
std::optional<T>instead of nullable pointers for optional parameters to express intent clearly.