The function of the decrement operator ( --) in C++ is to decrease the value of a variable by one. It is a unary operator, meaning it operates on a single operand, and it serves as a concise shorthand for the statement variable = variable - 1. The decrement operator is not limited to integers; it can be used with any modifiable numeric type, such as float and double, as well as with pointers.
The operator has two forms, which behave differently when used within a larger expression:
- Prefix decrement (
--x): The variable is decremented before its value is used in the expression. The expression then evaluates to the variable's new, decremented value. - Postfix decrement (
x--): The variable is decremented after its original value has been used in the expression. The expression first evaluates to the variable's original, unchanged value.
Prefix vs. postfix decrement in detail
| Feature | Prefix Decrement (--x) |
Postfix Decrement (x--) |
|---|---|---|
| Execution Order | The variable is decremented first, then its value is used in the expression. | The variable's original value is used in the expression, and then it is decremented. |
| Return Value | An lvalue containing the new, decremented value. | An rvalue containing the original, non-decremented value. |
| Efficiency | Generally considered more efficient for user-defined types (like iterators) because it modifies the object directly and returns a reference. Postfix creates and returns a temporary copy of the original value. | May be less efficient for complex objects due to the creation of a temporary object. |
| Readability | Preferred in simple, standalone statements like --i; or in complex expressions where the side-effect needs to be immediate. |
Often used in for loops to reduce the counter, as the order of operations is unambiguous. |
Practical examples
With basic numeric types
#include <iostream>
int main() {
int x = 5;
int y = 5;
// Prefix decrement: `--x`
// x becomes 4, and the expression evaluates to 4.
int result1 = --x;
std::cout << "x after prefix: " << x << ", result1: " << result1 << std::endl;
// Output: x after prefix: 4, result1: 4
// Postfix decrement: `y--`
// The expression evaluates to 5. Then y becomes 4.
int result2 = y--;
std::cout << "y after postfix: " << y << ", result2: " << result2 << std::endl;
// Output: y after postfix: 4, result2: 5
}
Use code with caution.
With pointers
Decrementing a pointer moves it to the preceding memory location. The size of this movement depends on the data type the pointer points to. A decrement of a pointer to an int moves the pointer back by sizeof(int) bytes, while a pointer to a double moves back by sizeof(double) bytes.
#include <iostream>
int main() {
int arr[] = {10, 20, 30};
int* ptr = &arr[2]; // `ptr` now points to the value 30
std::cout << "Value before decrement: " << *ptr << std::endl; // Output: 30
// Postfix decrement moves the pointer, but the original value is dereferenced
*ptr--;
std::cout << "Value after postfix decrement of pointer: " << *ptr << std::endl; // Output: 20
// Now ptr points to 20. Prefix decrement moves the pointer first.
*(--ptr);
std::cout << "Value after prefix decrement of pointer: " << *ptr << std::endl; // Output: 10
}
Use code with caution.
Common uses for decrement
-
Loop control: Decrement is often used to manage loop counters, especially in
forloops that count down from a specific value.cppfor (int i = 10; i > 0; i--) { // Countdown from 10 }Use code with caution.
-
Reverse iteration: When traversing an array or container backward, decrementing a pointer or iterator is the standard approach.cpp
int numbers[] = {1, 2, 3}; for (int i = 2; i >= 0; i--) { std::cout << numbers[i] << " "; } // Output: 3 2 1Use code with caution.
-
Pointer arithmetic: The decrement operator provides a clear way to adjust a pointer for iterating backward through arrays or memory blocks.
-
Iterator manipulation: The decrement operator is overloaded for many C++ Standard Library iterator types to move the iterator to the previous element in a sequence.
Considerations and potential issues
-
Undefined behavior: Mixing multiple increments or decrements of the same variable within a single expression can lead to undefined behavior because the order of operations is not guaranteed.cpp
int x = 5; int result = x-- + x--; // Undefined behaviorUse code with caution.
-
Readability in expressions: Using decrement within complex expressions can make the code harder to read and understand. It's often clearer to put the decrement on a separate line.
-
Overloading for user-defined types: C++ allows the decrement operator to be overloaded for custom classes. The implementation for prefix and postfix versions should reflect the standard behavior of the built-in types.
-
Inefficient post-decrement: For objects where creating a temporary copy is expensive (e.g., complex iterators), the prefix version (
--x) is more efficient because it avoids the copy.