How to use pointers correctly in modern C++
Share
Many developers, even after mastering the basics of C++, still feel uncomfortable when it comes to pointers. Some fear them, others overuse them — creating memory leaks and hard-to-debug issues. In modern C++, pointers remain an important part of the language, but the approach to them has changed significantly.
In this article, we’ll break down how to work with pointers correctly today — in 2026 — taking into account the capabilities of C++11, C++17, and C++20.
1. Why pointers are still needed
Pointers allow you to:
- Work with dynamic memory
- Pass large objects to functions without copying
- Implement polymorphism
- Build data structures (lists, trees, graphs)
However, modern C++ strongly recommends using raw pointers only in very limited cases.

2. Modern C++ rule: avoid raw pointers whenever possible
Instead of new and delete, almost always prefer:
// Instead of this int* ptr = new int(42); delete ptr; // Better to use auto value = std::make_unique<int>(42); // or std::shared_ptr<int> shared = std::make_shared<int>(42);
- std::unique_ptr — when the object has a single owner
- std::shared_ptr — when the object can have multiple owners
- std::weak_ptr — to break cycles in shared_ptr ownership
3. When raw pointers are still acceptable
Raw pointers (T*) can be used only in these situations:
- You are working with external APIs (e.g., C libraries)
- You are writing low-level code or a custom allocator
- You are implementing a data structure where maximum performance is critical
Even in these cases, it is recommended to use std::span (C++20) instead of raw pointers to arrays.
4. Common mistakes and how to avoid them
- Never return a pointer to a local variable
- Never use delete on arrays (always use delete[])
- Never forget to check for nullptr before dereferencing
- Never create dangling pointers
Correct modern approach example:
std::span<const int> processData(std::span<const int> data) {
// Safe work with data without taking ownership
return data;
}
5. Practical recommendations for 2026
- Use std::unique_ptr by default
- For array-like data — prefer std::vector or std::span
- For observation without ownership — use std::weak_ptr or plain references
- Avoid new and delete in regular application code
- Always prefer std::make_unique and std::make_shared
Following these simple rules makes your code safer, cleaner, and much easier to maintain in modern C++ projects.
If you’re still writing raw new/delete in 2026 — it’s time to switch to smart pointers and spans. Your future self (and your colleagues) will thank you.