← Back to C++ Course | Chapter 14: Memory Management | Lesson 6 of 6

C++ shared_ptr & weak_ptr

A shared_ptr lets several owners share one thing and cleans it up when the last owner leaves, like the last person turning off the lights. A weak_ptr watches without owning.
Syntax
cpp
#include <memory>

std::shared_ptr<data_type> pointer_name = std::make_shared<data_type>(value);
std::shared_ptr<data_type> copy = pointer_name;  // shared ownership
std::weak_ptr<data_type> observer = pointer_name;  // does not own

shared_ptr Basics

std::shared_ptr allows multiple pointers to jointly own the same dynamically allocated object, tracked via an internal reference count.

The object is only deleted once that count drops to zero, meaning the last shared_ptr to go out of scope is the one that actually frees the memory.

Example: shared_ptr Basics

cpp
// Include std::cout and std::cin
#include <iostream>
// Include smart pointers
#include <memory>

// Program execution starts in main()
int main() {
	// Use a shared_ptr: a reference-counted smart pointer
	std::shared_ptr<int> ptr(new int(5));
	// Print to the console with cout
	std::cout << *ptr << " count=" << ptr.use_count() << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}

Copying shared_ptr

Unlike unique_ptr, a shared_ptr can be freely copied -- each copy increments the shared reference count, and each destroyed copy decrements it.

This makes shared_ptr the right tool when an object's lifetime genuinely needs to be shared across multiple parts of a program, rather than owned by just one.

Example: Copying shared_ptr

cpp
// Include std::cout and std::cin
#include <iostream>
// Include smart pointers
#include <memory>

// Program execution starts in main()
int main() {
	// Use a shared_ptr: a reference-counted smart pointer
	std::shared_ptr<int> ptr1(new int(5));
	// Use a shared_ptr: a reference-counted smart pointer
	std::shared_ptr<int> ptr2 = ptr1;
	// Print to the console with cout
	std::cout << ptr1.use_count() << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}

make_shared

std::make_shared<T>(args) allocates the object and its reference-counting control block together in a single heap allocation, making it both faster and more exception-safe than constructing a shared_ptr from a separately new'd raw pointer.

Example: make_shared

cpp
// Include std::cout and std::cin
#include <iostream>
// Include smart pointers
#include <memory>

// Program execution starts in main()
int main() {
	// Use a shared_ptr: a reference-counted smart pointer
	auto ptr = std::make_shared<int>(42);
	// Print to the console with cout
	std::cout << *ptr << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}

The Circular Dependency Problem

If two objects hold shared_ptrs to each other, their reference counts can never reach zero -- each keeps the other alive indefinitely, even if nothing outside the pair references them anymore.

This reference cycle is a real memory leak that shared_ptr alone cannot detect or resolve.

Example: The Circular Dependency Problem

cpp
// Include std::cout and std::cin
#include <iostream>
// Include smart pointers
#include <memory>

// Define the type Node
class Node {
// Members below can be accessed from outside the class
public:
	std::shared_ptr<Node> next;
	~Node() { std::cout << "Node destroyed" << std::endl; }
};

// Program execution starts in main()
int main() {
	// Use a shared_ptr: a reference-counted smart pointer
	auto a = std::make_shared<Node>();
	// Use a shared_ptr: a reference-counted smart pointer
	auto b = std::make_shared<Node>();
	a->next = b;
	b->next = a;
	// Print to the console with cout
	std::cout << "Circular references created" << std::endl;
	return 0;
}

weak_ptr Basics

std::weak_ptr observes an object managed by a shared_ptr without incrementing its reference count, which is exactly how you break the circular-reference problem above.

Because the object it points to might already be gone, you must call lock() to obtain a temporary shared_ptr before safely accessing it.

Example: weak_ptr Basics

cpp
// Include std::cout and std::cin
#include <iostream>
// Include smart pointers
#include <memory>

// Program execution starts in main()
int main() {
	// Use a shared_ptr: a reference-counted smart pointer
	std::shared_ptr<int> shared = std::make_shared<int>(42);
	std::weak_ptr<int> weak = shared;
	// Print to the console with cout
	std::cout << shared.use_count() << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Creating circular shared_ptr references so the objects are never freed.
  2. Creating two separate shared_ptr from the same raw pointer, which causes a double delete.
  3. Using a weak_ptr directly without calling lock() first.
Chapter Summary
  • Memory management covers how programs allocate and release memory.
  • new and delete create and free memory, including dynamic arrays, and forgetting to free causes memory leaks.
  • unique_ptr, shared_ptr, and weak_ptr manage memory automatically.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.