Smart Pointers vs Raw Pointers
What's the difference between smart pointers and raw pointers, and when should I use each?
Smart pointers and raw pointers are both tools for managing memory in C++, but they have some key differences in terms of functionality and usage. Let's break down each type and discuss when to use them.
Raw Pointers
Raw pointers are the traditional C-style pointers. They're simple and lightweight, but they require manual memory management.
#include <iostream>
class Weapon {
public:
Weapon(std::string name)
: mName{std::move(name)} {}
~Weapon() {
std::cout << mName << " destroyed\n";
}
std::string mName;
};
int main() {
Weapon* sword = new Weapon("Excalibur");
// Use sword...
delete sword; // Remember to delete!
}
Raw pointers don't automatically free memory when they go out of scope, which can lead to memory leaks if not managed carefully.
Smart Pointers
Smart pointers, introduced in C++11, are objects that act like pointers but provide additional features, most notably automatic memory management. The two main types are std::unique_ptr
and std::shared_ptr
.
std::unique_ptr
std::unique_ptr
is for exclusive ownership. Only one unique_ptr
can own an object at a time.
#include <iostream>
#include <memory>
class Weapon {
public:
Weapon(std::string name)
: mName{std::move(name)} {}
~Weapon() {
std::cout << mName << " destroyed\n";
}
std::string mName;
};
int main() {
std::unique_ptr<Weapon> sword{
std::make_unique<Weapon>("Excalibur")};
// Use sword...
} // sword is automatically deleted here
Excalibur destroyed
std::shared_ptr
std::shared_ptr
allows multiple pointers to share ownership of an object. The object is deleted when the last shared_ptr
is destroyed.
#include <iostream>
#include <memory>
class Character {
public:
Character(std::string name)
: mName{std::move(name)} {}
~Character() {
std::cout << mName << " destroyed\n";
}
std::string mName;
};
int main() {
std::shared_ptr<Character> hero1{
std::make_shared<Character>("Anna")};
{
// Shared ownership
std::shared_ptr<Character> hero2 = hero1;
std::cout << "Heroes: " << hero1->mName
<< " and " << hero2->mName << "\n";
// hero2 goes out of scope, but object
// isn't deleted yet
}
std::cout << "Hero 1 still alive\n";
}
// hero1 goes out of scope, Character
// object is deleted
Heroes: Anna and Anna
Hero 1 still alive
Anna destroyed
When to Use Each
Use raw pointers when:
- You're working with legacy code or APIs that require raw pointers
- You need to pass a non-owning pointer (consider
std::weak_ptr
forshared_ptr
objects) - You're implementing low-level data structures or when performance is absolutely critical
Use smart pointers when:
- You want automatic memory management to prevent leaks
- You're designing new code and have control over the ownership model
- You need shared ownership (
std::shared_ptr
) or exclusive ownership (std::unique_ptr
)
In modern C++, it's generally recommended to prefer smart pointers over raw pointers for most scenarios. They provide safety and convenience without significant performance overhead. However, understanding raw pointers is still crucial for working with existing codebases and certain low-level operations.
Pointers
This lesson provides a thorough introduction to pointers in C++, covering their definition, usage, and the distinction between pointers and references