cppreference.com

Std:: shared_ptr.

std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer. Several shared_ptr objects may own the same object. The object is destroyed and its memory deallocated when either of the following happens:

  • the last remaining shared_ptr owning the object is destroyed;
  • the last remaining shared_ptr owning the object is assigned another pointer via operator= or reset() .

The object is destroyed using delete-expression or a custom deleter that is supplied to shared_ptr during construction.

A shared_ptr can share ownership of an object while storing a pointer to another object. This feature can be used to point to member objects while owning the object they belong to. The stored pointer is the one accessed by get() , the dereference and the comparison operators. The managed pointer is the one passed to the deleter when use count reaches zero.

A shared_ptr may also own no objects, in which case it is called empty (an empty shared_ptr may have a non-null stored pointer if the aliasing constructor was used to create it).

All specializations of shared_ptr meet the requirements of CopyConstructible , CopyAssignable , and LessThanComparable and are contextually convertible to bool .

All member functions (including copy constructor and copy assignment) can be called by multiple threads on different instances of shared_ptr without additional synchronization even if these instances are copies and share ownership of the same object. If multiple threads of execution access the same instance of shared_ptr without synchronization and any of those accesses uses a non-const member function of shared_ptr then a data race will occur; the std::atomic<shared_ptr> can be used to prevent the data race.

[ edit ] Member types

[ edit ] member functions, [ edit ] non-member functions, [ edit ] helper classes, [ edit ] deduction guides (since c++17), [ edit ] notes.

The ownership of an object can only be shared with another shared_ptr by copy constructing or copy assigning its value to another shared_ptr . Constructing a new shared_ptr using the raw underlying pointer owned by another shared_ptr leads to undefined behavior.

std::shared_ptr may be used with an incomplete type T . However, the constructor from a raw pointer ( template < class Y > shared_ptr ( Y * ) ) and the template < class Y > void reset ( Y * ) member function may only be called with a pointer to a complete type (note that std::unique_ptr may be constructed from a raw pointer to an incomplete type).

The T in std :: shared_ptr < T > may be a function type: in this case it manages a pointer to function, rather than an object pointer. This is sometimes used to keep a dynamic library or a plugin loaded as long as any of its functions are referenced:

[ edit ] Implementation notes

In a typical implementation, shared_ptr holds only two pointers:

  • the stored pointer (one returned by get() );
  • a pointer to control block .

The control block is a dynamically-allocated object that holds:

  • either a pointer to the managed object or the managed object itself;
  • the deleter (type-erased);
  • the allocator (type-erased);
  • the number of shared_ptr s that own the managed object;
  • the number of weak_ptr s that refer to the managed object.

When shared_ptr is created by calling std::make_shared or std::allocate_shared , the memory for both the control block and the managed object is created with a single allocation. The managed object is constructed in-place in a data member of the control block. When shared_ptr is created via one of the shared_ptr constructors, the managed object and the control block must be allocated separately. In this case, the control block stores a pointer to the managed object.

The pointer held by the shared_ptr directly is the one returned by get() , while the pointer/object held by the control block is the one that will be deleted when the number of shared owners reaches zero. These pointers are not necessarily equal.

The destructor of shared_ptr decrements the number of shared owners of the control block. If that counter reaches zero, the control block calls the destructor of the managed object. The control block does not deallocate itself until the std::weak_ptr counter reaches zero as well.

In existing implementations, the number of weak pointers is incremented ( [1] , [2] ) if there is a shared pointer to the same control block.

To satisfy thread safety requirements, the reference counters are typically incremented using an equivalent of std::atomic::fetch_add with std::memory_order_relaxed (decrementing requires stronger ordering to safely destroy the control block).

[ edit ] Example

Possible output:

[ edit ] See also

  • Recent changes
  • Offline version
  • What links here
  • Related changes
  • Upload file
  • Special pages
  • Printable version
  • Permanent link
  • Page information
  • In other languages
  • This page was last modified on 30 January 2024, at 14:09.
  • This page has been accessed 4,938,857 times.
  • Privacy policy
  • About cppreference.com
  • Disclaimers

Powered by MediaWiki

  • C++ Data Types
  • C++ Input/Output
  • C++ Pointers
  • C++ Interview Questions
  • C++ Programs
  • C++ Cheatsheet
  • C++ Projects
  • C++ Exception Handling
  • C++ Memory Management
  • Compound Statements in C++
  • Rethrowing an Exception in C++
  • Variable Shadowing in C++
  • Condition Variables in C++ Multithreading
  • C++23 <print> Header
  • Literals In C++
  • How to Define Constants in C++?
  • C++ Variable Templates
  • Introduction to GUI Programming in C++
  • Concurrency in C++
  • Hybrid Inheritance In C++
  • Dereference Pointer in C
  • Nested Inline Namespaces In C++20
  • C++20 std::basic_syncbuf
  • std::shared_mutex in C++
  • Partial Template Specialization in C++
  • Pass By Reference In C
  • Address Operator & in C
  • Attendance Marking System in C++

shared_ptr in C++

std::shared_ptr is one of the smart pointers introduced in C++11. Unlike a simple pointer, it has an associated control block that keeps track of the reference count for the managed object. This reference count is shared among all the copies of the shared_ptr instances pointing to the same object, ensuring proper memory management and deletion.

Prerequisites: Pointers in C++ , Smart Pointers in C++ .

shared_ptr-in-CPP

Shared Pointer in C++

Syntax of std::shared_ptr

The shared_ptr of type T can be declared as:

Initialization of shared_ptr Objects

We can initialize the shared_ptr using the following methods:

1. Initialization using a New Pointer

2. Initialization using existing Pointer

Member Methods of shared_ptr

Following are some members associated with shared_ptr:

Examples of std::shared_ptr

Example 3: implementing a linked list using std::shared_ptr, please login to comment..., similar reads.

  • Geeks Premier League 2023
  • Geeks Premier League
  • 10 Best Slack Integrations to Enhance Your Team's Productivity
  • 10 Best Zendesk Alternatives and Competitors
  • 10 Best Trello Power-Ups for Maximizing Project Management
  • Google Rolls Out Gemini In Android Studio For Coding Assistance
  • 30 OOPs Interview Questions and Answers (2024)

Improve your Coding Skills with Practice

 alt=

What kind of Experience do you want to share?

std::weak_ptr

Defined in header <memory> .

std::weak_ptr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by std::shared_ptr . It must be converted to std::shared_ptr in order to access the referenced object.

std::weak_ptr models temporary ownership: when an object needs to be accessed only if it exists, and it may be deleted at any time by someone else, std::weak_ptr is used to track the object, and it is converted to std::shared_ptr to assume temporary ownership. If the original std::shared_ptr is destroyed at this time, the object's lifetime is extended until the temporary std::shared_ptr is destroyed as well.

Another use for std::weak_ptr is to break reference cycles formed by objects managed by std::shared_ptr . If such cycle is orphaned (i.e., there are no outside shared pointers into the cycle), the shared_ptr reference counts cannot reach zero and the memory is leaked. To prevent this, one of the pointers in the cycle can be made weak.

Member types ​

Member functions ​, modifiers ​, observers ​, non-member functions ​, helper classes ​, deduction guides (since c++17) ​.

Like std::shared_ptr , a typical implementation of weak_ptr stores two pointers:

  • a pointer to the control block; and
  • the stored pointer of the std::shared_ptr it was constructed from.

A separate stored pointer is necessary to ensure that converting a std::shared_ptr to weak_ptr and then back works correctly, even for aliased std::shared_ptr s. It is not possible to access the stored pointer in a weak_ptr without locking it into a std::shared_ptr .

Demonstrates how lock is used to ensure validity of the pointer.

Defect reports ​

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

  • Member types
  • Member functions
  • Non-member functions
  • Helper classes
  • Deduction guides (since C++17)
  • Defect reports

CodersLegacy

C++ Smart Pointers (Shared, Unique and Weak Pointers)

Pointers are a great asset, and can be used to solve a variety of different problems. However, Pointers are not very easy to use, and when used for complex problems, even a slight mistake can ruin everything. Tracing the memory and addresses, ensuring that there are no dangling pointers etc, can be a rather daunting tasks. Luckily, C++ has introduced the concept of Smart Pointers to help us.

Like Vectors, Smart Pointers are templates , which means when we create a Smart pointer, we need to specify the type to which the pointer will point.

Why do we need Smart Pointers in C++?

Unlike stack memory, dynamically allocated memory must be manually deleted. Whenever we allocate memory on the heap using the new keyword, we have to manually free it later using the delete keyword . This can be quite the hassle in larger applications, and often cause problems that are hard to track down.

In general, Dynamically allocated memory is tricky to handle. Luckily C++ gives us a better way of managing this with “Smart Pointers”. These pointers, as the name implies are able to automatically delete themselves when they go out of scope, removing the need for you to do it yourself. This saves us from many issues that using the new and delete keywords can bring.

There are three types of smart pointers in C++, shared pointers, unique pointers and weak pointers. We’ll discuss each of them individually in the sections below.

Shared Pointers

The first main type of Smart Pointer, is the Shared Pointer. It’s a type of pointer that allows multiple pointers to refer to the same object. Shared Pointers use what we call reference counts to keep track of the number of pointers to an object. Everytime a new pointer points to the object, the reference count is incremented.

The Object is deleted when this reference count drops to 0, and the memory is then freed. The reference count drops when shared pointers are either destroyed, or they go out of scope. When the last shared pointer to an object is destroyed, the shared pointer class deletes the object.

Creating a Shared Pointer

Let’s create some shared pointers. The below examples should help you understand the syntax.

We can now begin giving this pointer something to point to. While we can use the regular methods as well as the new keyword, the safest way (and most recommended) way is to use the make_shared function. This function allocates and initializes an object in dynamic memory and returns a shared pointer that points to that memory. Pretty similar to the new function.

Everything else about the shared pointer is just like that of a regular pointer. You can use the * operator on them, you can assign an address to them with &, etc.

Shared Pointer and it’s Scope

A small example we have made to demonstrate how the shared pointer, and reference counts work.

When we created the first pointer, p1 , reference count was set to 1. After creating a new pointer, p2 , in the if statement block, the reference count was incremented to 2 . Once we exited that scope of the if statement, the pointer p2 was destroyed and the reference count dropped to 1 again.

Unique Pointer

The second type of Smart Pointer available in C++.

The difference between the Unique Pointer and the shared Pointer is that unlike shared, where an object can have multiple shared pointers, only one unique pointer can be pointing to an object at any given time. Hence the name “Unique”.

When the Unique pointer, pointing to an object is destroyed, the object is also destroyed, freeing up memory. There is no “ make_shared ” equivalent for unique_ptr , so we will have to make do with new .

Creating Unique Pointers

There isn’t any special function for creating unique pointers, leaving us with the new keyword.

If we uncomment the line commented line in the above code, there will be an error. Why? Because there cannot be more than one pointer pointing to the same object.

Note: There is one exception to the “only one pointer at a time”. We can copy or assign a unique_ptr that is about to be destroyed. For example, when we return a unique pointer from a function. The compiler will know that the object is about to be destroyed, and performs a special copy.

Weak Pointer

Weak Pointers are the third type of Smart Pointers in C++.

The Weak Pointer class is a sort of extension, or companion of the Shared Pointer. It does not manage the life time of the object that it points to, unlike the other two smart pointers. It instead, points to an object that is managed by a shared pointer, but unlike a regular shared pointer, it does not increase the reference count. This is why it’s called a “weak” pointer.

You can’t directly use a Weak Pointer, and need to use the lock() function. This returns a shared pointer to the object it was pointing to, if the object still exists. If the reference count has dropped to zero however, and the object is deleted, it will return NULL.

Using Weak Pointers

Here is the first example we have on Weak Pointers, which is meant to emphasize that Weak Pointers have no effect on the Reference Count. Even after initializing the Weak Pointer with the address held by the shared pointer, the reference count remained one.

Here we have another example where we demonstrate the Connection of the Weak Pointer with the object it’s pointing to.

The int object 53 has been created in the if statement below. Once the if statement’s code block ends, this object is destroyed as well due to going out of scope. After it has been destroyed, we can no longer access it. We have attempted to access it twice, once while we it’s still alive, and once after it’s been destroyed.

These are useful for scenarios where you don’t want to increment the reference count, yet hold a connection to the object.

This marks the end of the C++ Smart Pointers tutorial. Any suggestions or contributions for CodersLegacy are more than welcome. Questions regarding the tutorial content can be asked in the comments section below.

guest

Shared Pointers using std::shared_ptr

Professional c++.

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

3D Character Concept Art

Ryan McCombe

So far in this section, we’ve coverered how smart pointers are tools for managing dynamically allocated memory, ensuring that memory is automatically deallocated when it is no longer needed.

The C++ standard library provides a few variations of smart pointers. std::unique_ptr and std::shared_ptr are the most commonly used, but they serve different purposes:

Unique Pointers

Unique pointers, such as std::unique_ptr enforces unique ownership of the memory resource it manages. It implies that only one unique pointer can point to a specific resource at any time.

When the std::unique_ptr is destroyed or revokes its ownership through the std::move() , release() or reset() methods, the resource it points to is automatically deallocated. This type of smart pointer is lightweight and efficient, making it an ideal choice for most single-owner scenarios.

We covered unique pointers in detail a dedicated lesson:

3D Character Concept Art

Memory Ownership, Smart Pointers and std::unique_ptr

Shared Pointers

Unlike std::unique_ptr , std::shared_ptr allows multiple pointers to share ownership of a single resource. The resource is only deallocated when the last std::shared_ptr pointing to it is destroyed or reset.

This shared ownership is managed through reference counting - an internal mechanism that keeps track of how many std::shared_ptr instances are managing the same resource. This comes at a performance cost, so in general, std::unique_ptr , should be our default choice of smart pointer.

However, there are scenarios where an object needs to be accessed and managed by multiple owners. In such cases, std::shared_ptr becomes invaluable, and we’ll cover it in detail in this lesson.

Similar to the previous lesson, we’ll be using the following Character class to demonstrate how shared pointers work.

It has a simple constructor and destructor that logs when objects are created and destroyed, so we can better understand when these steps happen:

std::make_shared()

We previously saw how the helper function std::make_unique created a std::unique_ptr for us. Predictably, we also have std::make_shared to create a std::shared_ptr :

The std::make_shared() function creates an object of the type specified between the < and > tokens, allocated in dynamic memory. It returns a std::shared_ptr of that same type.

For example, std::make_shared<Character>() will create a Character in dynamic memory, and return a std::shared_ptr<Character> that points to it.

Any function arguments passed to std::make_shared() are forwarded to the underlying type’s constructor:

Using Shared Pointers

In most ways, shared pointers can be used in the same way as unique pointers.

Dereferencing Shared Pointers using * and ->

We can dereference shared pointers using the * and ->  operators:

Accessing the Raw Pointer using get()

We can access the raw memory address being managed by a shared pointer using the get()  method:

Transferring Ownership using std::move()

A shared pointer can also transfer its ownership of a resource using std::move() :

As before with unique pointers, note how our Character is now being deleted at the end of the TakeOwnership() function, rather than at the end of main :

Swapping Ownership using swap()

We also have access to swap() , allowing two shared pointers to exchange ownership of the objects they’re managing:

Resetting Ownership using reset()

Similar to unique pointers, a shared pointer can revoke its ownership of the underlying resource using reset() . Below, note how our Character is automatically deleted as soon as our shared pointer revokes its ownership over it:

The reset() method can also be used to replace the managed object with a new one of the same type (or convertible to the same type):

Unlike the unique pointer variation, the shared pointers reset() method may not cause the object to be deleted.

Smart pointers only delete the underlying resource if the resource has no owners .

With unique pointers, by design, the resource only has one owner. So, after calling reset() on a unique pointer, the resource will have no owners, so it will automatically be deleted.

However, there can be multiple shared pointers sharing ownership of the same resource. A single shared pointer being deleted, or revoking its ownership through reset() or move() , doesn’t necessarily mean the underlying resource will be deleted.

There may be other shared pointers that still have an ownership stake over it. It will only be destroyed after all of those shared pointers are destroyed, or they give up ownership.

In the rest of this lesson, we show how we can set up a collection of shared pointers such that they can all share ownership of an underlying resource.

Sharing Ownership

The key difference between unique and shared pointers is that, predictably, shared pointers can be shared. This is done simply by creating copies of them:

Most commonly, these copies are created by passing the shared pointer by value into a function, or setting it as a member variable on some object using the assignment operator = :

This is the key mechanism that allows a resource to have multiple owners. Every function or object that has a copy of the shared pointer is considered an owner.

The underlying resource is deleted only when all of its owners are deleted.

Getting the Owner Count using use_count()

We can see how many owners a shared pointer has using the use_count() class function:

A more complex example is below, showing the effect of functions like std::move() and reset() on the the ownership model:

Pitfall: Not Copying Shared Pointers

The most common mistake people make with shared pointers is not creating them correctly.

The mechanism that enables a collection of shared pointers to co-ordinate their ownership is predicated on new pointers in the collection being created from existing pointers.

Creating a new shared pointer in any other way will bypass this mechanism, even if the shared pointer happens to be pointing to the same object.

For example, the following code is not copying the shared pointer:

In the above code, even though Pointer1 and Pointer2 are managing the same object, they’re not aware of each other. This means they cannot correctly determine when the object should be deleted, which in turn will cause memory issues.

Therefore, when we want to share ownership of an object, we should ensure we’re instantiating new pointers from existing ones:

Shared Pointer Casting

Just like raw pointers can be cast to other types with dynamic_cast and static_cast , so too can shared pointers.

We have dedicated lessons on static and dynamic casting available here:

3D art showing a fantasy monster

Downcasting

The only difference is, for shared pointers, we instead use std::dynamic_pointer_cast and std::static_pointer_cast . Rather than returning raw pointers, these functions return std::shared_ptr  instances.

If std::dynamic_pointer_cast fails, it returns an "empty" shared pointer - that is, one that is not managing any underlying object.

Such a pointer evaluates to false when converted to a boolean therefore code using std::dynamic_pointer_cast looks very similar to code using dynamic_cast :

Owning and Pointing At Different Objects

Shared pointers have an interesting feature where the object they are sharing ownership over does not necessarily need to be the same object they are pointing at.

This is enabled through an alternative std::shared_ptr constructor, sometimes referred to as the aliasing constructor , that accepts two arguments:

  • The object to own , in the form of a std::shared_ptr to copy
  • The object to point at, in the form of a memory address

In the following contrived example, we show the mechanism of this using integers. Alias is managing the dynamically allocated integer that has the value of 1 , but is pointing at the stack-allocated integer that has a value of 2 :

The most useful application of this is to create a pointer that shares ownership of an object, whilst pointing to a specific member of that same object.

For example, below we have a smart pointer that points to a character’s Name field, but shares ownership of the Character as a whole.

This gives us a pointer we can use to directly access the specific object property we want, whilst also preventing the object itself from being deleted before we’re done with it:

As we conclude this lesson, we've equipped ourselves with a thorough understanding of shared pointers, and the standard library’s std::shared_ptr in particular. We've seen how this type of smart pointer is using in scenarios where multiple ownership of a dynamic resource is necessary.

Key Points:

  • The Role of Shared Pointers and std::shared_ptr : We've learned that std::shared_ptr is used when an object needs multiple owners, and it keeps track of how many pointers own the resource.
  • Practical Functions : Functions like std::make_shared() , get() , reset() , and swap() offer us practical ways to manage and interact with shared pointers.
  • Shared Pointer Memory Management : Through std::shared_ptr , we've seen another example of how smart pointers handle automatic memory management, and the implications of multiple ownerships on that process.
  • Avoiding Common Mistakes : We discussed common pitfalls such as improper copying of shared pointers and how to avoid them.

With this knowledge, we’re now even better prepared to write safer and more managable programs

Looking Ahead: Weak Pointers

In our next lesson, we'll dive into std::weak_ptr , another type of smart pointer. We'll explore how weak pointers work, their relationship with shared pointers, and their practical applications.

This lesson will further enhance our understanding of memory management in C++, preparing us for more advanced projects.

Was this lesson useful?

Edit history.

4 months ago — Added additional content, AI assistant, table of contents and references

12 months ago — First Published

References and Related Content

StudyPlan.dev - Memory Ownership with Smart Pointers https://www.studyplan.dev/pro-cpp/smart-pointers

cppreference.com - std::shared_ptr https://en.cppreference.com/w/cpp/memory/shared_ptr

Microsoft - shared_ptr Class https://learn.microsoft.com/en-us/cpp/standard-library/shared-ptr-class

An introduction to shared memory ownership using std::shared_ptr

A computer programmer

Whirlwind Tour of C++ Basics

  • 1 . Variables, Types and Operators
  • 2 . Introduction to Functions
  • 3 . Namespaces, Includes, and the Standard Library
  • 4 . Conditionals and Loops
  • 5 . Classes, Structs and Enums
  • 6 . Preprocessor, Build Process, and Header Files
  • 7 . References and Pointers
  • 8 . Operator Overloading
  • 9 . Polymorphism
  • 10 . Odds and Ends

Memory Management

  • 11 . Memory Management - The Stack
  • 12 . Dynamic Memory - The Free Store / Heap
  • 13 . Memory Ownership, Smart Pointers and std::unique_ptr
  • 15 . Weak Pointers with std::weak_ptr
  • 16 . Copy Semantics and Return Value Optimization
  • 17 . Move Semantics
  • 18 . Value Categories (L-Values and R-Values)
  • 19 . Type Aliases
  • 20 . Class Templates
  • 21 . Templates and Header Files
  • 22 . Compile-Time Evaluation
  • 23 . Variable Templates
  • 24 . Function Templates
  • 25 . Member Function Templates
  • 26 . Template Specialization

Type Traits and Concepts

  • 27 . Understanding Overload Resolution
  • 28 . Type Traits: Compile-Time Type Analysis
  • 29 . Using SFINAE to Control Overload Resolution
  • 30 . Concepts in C++20
  • 31 . Creating Custom Concepts
  • 32 . Using Concepts with Classes
  • 33 . Run Time Type Information (RTTI) and typeid()

Exceptions and Error Handling

  • 34 . Errors and Assertions
  • 35 . Exceptions: throw , try and catch
  • 36 . Exception Types
  • 37 . std::terminate and the noexcept specifier
  • 38 . Storing and Rethrowing Exceptions
  • 39 . Nested Exceptions
  • 40 . Function Try Blocks

Arrays and Linked Lists

  • 41 . Static Arrays using std::array
  • 42 . C-Style Arrays
  • 43 . Array Spans and std::span
  • 44 . Multidimensional Arrays and std::mdspan
  • 45 . Algorithm Analysis and Big O Notation
  • 46 . Data Structures and Algorithms
  • 47 . Iterators
  • 48 . Working with Linked Lists using std::forward_list

Hash Sets and Hash Maps

  • 49 . Hashing and std::hash
  • 50 . Implementing Hash Sets using std::unordered_set
  • 51 . Using std::pair
  • 52 . Implementing Hash Maps using std::unordered_map

Standard Library Data Structures

  • 53 . Nullable Values using std::optional
  • 54 . Unions and std::variant
  • 55 . Void Pointers and std::any
  • 56 . Tuples and std::tuple
  • 57 . Introduction to Queues and std::queue
  • 58 . Priority Queues using std::priority_queue
  • 59 . Introduction to Stacks using std::stack
  • 60 . Double-Ended Queues using std::deque

Working with Functions

  • 61 . First Class Functions
  • 62 . Function Pointers
  • 63 . Function Objects (Functors)
  • 64 . Lambdas
  • 65 . Standard Library Function Helpers
  • 66 . Function Binding and Partial Application
  • 67 . Trailing Return Types
  • 68 . Recursion and Memoization
  • 69 . Variadic Functions
  • 70 . Fold Expression
  • 71 . Perfect Forwarding and std::forward

Iterators and Ranges

  • 72 . Iterators and Ranges
  • 73 . Implementing Ranges for Custom Types
  • 74 . Defining Ranges using Sentinels
  • 75 . Creating Custom Iterators using C++20 Concepts
  • 76 . Iterator and Range-Based Algorithms
  • 77 . Projection Functions
  • 78 . Standard Library Views
  • 79 . Creating Views using std::ranges::subrange
  • 80 . 8 Key Standard Library Algorithms
  • 81 . Parallel Algorithm Execution

Standard Library Algorithms

  • 82 . Search Algorithms
  • 83 . Binary Search in C++
  • 84 . Counting Algorithms
  • 85 . Minimum and Maximum Algorithms
  • 86 . Movement Algorithms
  • 87 . Copying Algorithms
  • 88 . Removal Algorithms
  • 89 . Replacement Algorithms
  • 90 . Partition Algorithms
  • 91 . Set Algorithms
  • 92 . Comparison Algorithms
  • 93 . The Reduce and Accumulate Algorithms
  • 94 . C++23 Fold Algorithms

Objects, Classes and Modules

  • 95 . Internal and External Linkage
  • 96 . Static Class Variables and Functions
  • 97 . Friend Classes and Functions
  • 98 . Mutable Class Members
  • 99 . Multiple Inheritance and Virtual Base Classes
  • 100 . Pure Virtual Functions, Abstract Classes, and Interfaces
  • 101 . List, Aggregate, and Designated Initialization
  • 102 . User Defined Conversions
  • 103 . User Defined Literals
  • 104 . The Spaceship Operator and Expression Rewriting
  • 105 . C++20 Modules

Strings and Streams

  • 106 . Characters, Unicode and Encoding
  • 107 . Working with C-Style Strings
  • 108 . A Deeper Look at the std::string Class
  • 109 . Manipulation and Memory Management of std::string
  • 110 . Regular Expressions
  • 111 . Regex Capture Groups
  • 112 . String Views
  • 113 . Working with String Views
  • 114 . Output Streams
  • 115 . String Streams
  • 116 . Input Streams

Files and Serialization

  • 117 . Working with the File System
  • 118 . File System Paths
  • 119 . Directory Iterators
  • 120 . File Streams

Libraries and Dependencies

  • 121 . Installing vcpkg on Windows
  • 122 . Using JSON in Modern C++
  • 123 . Using HTTP in Modern C++
  • 124 . Binary Serialization using Cereal

This course includes:

  • 124 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ

Weak Pointers with std::weak_ptr

3D Character Concept Art

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

How to: Create and Use shared_ptr instances

  • 12 contributors

The shared_ptr type is a smart pointer in the C++ standard library that is designed for scenarios in which more than one owner needs to manage the lifetime of an object. After you initialize a shared_ptr you can copy it, pass it by value in function arguments, and assign it to other shared_ptr instances. All the instances point to the same object, and share access to one "control block" that increments and decrements the reference count whenever a new shared_ptr is added, goes out of scope, or is reset. When the reference count reaches zero, the control block deletes the memory resource and itself.

The following illustration shows several shared_ptr instances that point to one memory location.

Diagram showing two shared_ptr instances pointing to one memory location.

The first diagram shows a shared pointer, P1, that points to a MyClass instance as well as a control block with ref count = 1. The second diagram shows the addition of another shared pointer, P2, which also points to the MyClass instance and to the shared control block, which now has a ref count of 2.

Example setup

The examples that follow all assume that you've included the required headers and declared the required types, as shown here:

Whenever possible, use the make_shared function to create a shared_ptr when the memory resource is created for the first time. make_shared is exception-safe. It uses the same call to allocate the memory for the control block and the resource, which reduces the construction overhead. If you don't use make_shared , then you have to use an explicit new expression to create the object before you pass it to the shared_ptr constructor. The following example shows various ways to declare and initialize a shared_ptr together with a new object.

The following example shows how to declare and initialize shared_ptr instances that take on shared ownership of an object that was allocated by another shared_ptr . Assume that sp2 is an initialized shared_ptr .

shared_ptr is also helpful in C++ Standard Library containers when you're using algorithms that copy elements. You can wrap elements in a shared_ptr , and then copy it into other containers with the understanding that the underlying memory is valid as long as you need it, and no longer. The following example shows how to use the remove_copy_if algorithm on shared_ptr instances in a vector.

You can use dynamic_pointer_cast , static_pointer_cast , and const_pointer_cast to cast a shared_ptr . These functions resemble the dynamic_cast , static_cast , and const_cast operators. The following example shows how to test the derived type of each element in a vector of shared_ptr of base classes, and then copies the elements and display information about them.

You can pass a shared_ptr to another function in the following ways:

Pass the shared_ptr by value. This invokes the copy constructor, increments the reference count, and makes the callee an owner. There's a small amount of overhead in this operation, which may be significant depending on how many shared_ptr objects you're passing. Use this option when the implied or explicit code contract between the caller and callee requires that the callee be an owner.

Pass the shared_ptr by reference or const reference. In this case, the reference count isn't incremented, and the callee can access the pointer as long as the caller doesn't go out of scope. Or, the callee can decide to create a shared_ptr based on the reference, and become a shared owner. Use this option when the caller has no knowledge of the callee, or when you must pass a shared_ptr and want to avoid the copy operation for performance reasons.

Pass the underlying pointer or a reference to the underlying object. This enables the callee to use the object, but doesn't enable it to share ownership or extend the lifetime. If the callee creates a shared_ptr from the raw pointer, the new shared_ptr is independent from the original, and doesn't control the underlying resource. Use this option when the contract between the caller and callee clearly specifies that the caller retains ownership of the shared_ptr lifetime.

When you're deciding how to pass a shared_ptr , determine whether the callee has to share ownership of the underlying resource. An "owner" is an object or function that can keep the underlying resource alive for as long as it needs it. If the caller has to guarantee that the callee can extend the life of the pointer beyond its (the function's) lifetime, use the first option. If you don't care whether the callee extends the lifetime, then pass by reference and let the callee copy it or not.

If you have to give a helper function access to the underlying pointer, and you know that the helper function uses the pointer and return before the calling function returns, then that function doesn't have to share ownership of the underlying pointer. It just has to access the pointer within the lifetime of the caller's shared_ptr . In this case, it's safe to pass the shared_ptr by reference, or pass the raw pointer or a reference to the underlying object. Passing this way provides a small performance benefit, and may also help you express your programming intent.

Sometimes, for example in a std::vector<shared_ptr<T>> , you may have to pass each shared_ptr to a lambda expression body or named function object. If the lambda or function doesn't store the pointer, then pass the shared_ptr by reference to avoid invoking the copy constructor for each element.

The following example shows how shared_ptr overloads various comparison operators to enable pointer comparisons on the memory that is owned by the shared_ptr instances.

Smart Pointers (Modern C++)

Was this page helpful?

Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see: https://aka.ms/ContentUserFeedback .

Submit and view feedback for

Additional resources

shared_ ptr - basics and internals with examples

An introduction to shared_ptr's basics and internals through examples.

assign shared pointer to weak pointer

1. Overview

The C++11 std::shared_ptr< T > is a shared ownership smart pointer type. Several shared_ptr instances can share the management of an object's lifetime through a common control block . The managed object is deleted when the last owning shared_ptr is destroyed (or is made to point to another object). Memory management by shared_ptr is deterministic because the timing of a managed object's destruction is predictable and in the developer's control. Hence, std::shared_ptr brings deterministic automatic memory management to C++, without the overhead of garbage collection. Here is a basic example of shared_ptr :

This article is specific to general usage and internals of shared_ptr . It does not cover the fundamentals of smart pointers and assumes that the reader is familiar with those. Having looked at the basic usage, let's move on to the internals of shared_ptr that make it work.

2. Internals

In a typical implementation, a shared_ptr contains only two pointers: a raw pointer to the managed object that is returned by get() , and a pointer to the control block. A shared_ptr control block at least includes a pointer to the managed object or the object itself, a reference counter, and a weak counter. And depending on how a shared_ptr is initialized, the control block can also contain other data, most notably, a deleter and an allocator. The following figure corresponds to the example in the previous section. It shows the conceptual memory layout of the two shared_ptr instances managing the object:

shared_ptr control block

Next, we talk about the details of the most relevant parts of the control block. You would see that the memory layout of shared_ptr can deviate from the above illustration depending on how it is constructed.

2.1. Pointer to Managed Object (or Managed Object)

A control block contains a pointer to the managed object, which is used for deleting the object. One interesting fact is that the managed pointer in the control block could be different in type (and even value) from the raw pointer in the shared_ptr . This leads to a few fascinating use cases. In the following example, the types of the raw pointer and the managed pointer are different, but they are compatible and have the same values:

The inheritance example above is rather contrived. It shows that despite the destructor being not virtual , the correct derived class ( B ) destructor is invoked when the base class ( A ) shared_ptr is reset . That works because the control block is destroying the object through B* , not through the raw pointer A* . Nevertheless, the destructor should be declared virtual in the classes that are meant to be used polymorphically. This example intends to merely show how a shared_ptr works.

There is an even more exotic aliasing constructor of shared_ptr that can initialize a shared_ptr from a raw pointer and an unrelated shared_ptr . Consequently, an aliasing constructor can produce a shared_ptr that shares the management of one object but points to another object (usually a subobject of the managed object). For instance:

The in-depth treatment of aliasing constructor deserves its own space. I encourage you to check out " Aliasing constructed shared_ptr as key of map or set " for a more persuasive use case.

There is more discussion about the managed object pointer in the 'Deleter' section below when we talk about the type erasure .

Before we delve into more intricate details, let's talk about the std::make_shared . We mentioned above that the control block could either contain a pointer to the managed object or the object itself. The control block is dynamically allocated. Constructing the managed object in-place within the control block can avoid the two separate memory allocations for the object and the control block, resulting in an uncomplicated control block and better performance. The std::make_shared is a preferred way to construct a shared_ptr because it builds the managed object within the control block:

2.2. Reference Counter

The reference counter, which is incremented and decremented atomically, tracks the number of owning shared_ptr instances. The reference count increases as a new shared_ptr is constructed, and it decreases as an owning shared_ptr is destroyed. One exception to that is the reference count is left unchanged when a shared_ptr is moved because the move-constructor transfers the ownership from the source to the newly constructed shared_ptr . The managed object is disposed of when the reference count reaches zero.

std::shared_ptr ownership is also affected by the copy and move assignment operators. The copy assignment operator decreases the reference count of the destination (LHS) shared_ptr and increases the reference count of the source (RHS) shared_ptr . Whereas, the move assignment operator decreases the reference count of the destination (LHS) but does not change the reference count of the source (RHS).

Let's explore another example that exhibits the lifecycle of an object managed by a few shared_ptr instances. As you go through the code, refer the following figure for the different stages:

shared_ptr object lifecycle

2.3. Weak Counter

A control block also keeps the count of weak_ptr associated with it in a weak counter. An std::weak_ptr is a smart pointer that serves as a weak reference to an std::shared_ptr managed object. When a weak_ptr is created from a shared_ptr , it refers to the same control block but does not share the ownership of the managed object. It is not possible to directly access the managed object through a weak_ptr . A weak_ptr must be copied to a shared_ptr to acquire access to the managed object.

The following multithreaded example shows how a shared_ptr can be created from a weak_ptr as long as the managed object is alive. A reader thread periodically tries to acquire a shared_ptr< std::atomic_int > from a weak_ptr< std::atomic_int > and logs the value. If the reader thread cannot acquire a shared_ptr in an iteration, it exits. A writer thread periodically changes the shared_ptr managed std::atomic_int value a few times and exits. When the writer thread exits, the shared_ptr held by it is destroyed, and the reader thread can no longer get a shared_ptr from its weak_ptr , which makes the reader thread to also exit. The program terminates when both the threads exit:

The weak count is the number of existing weak_ptr . The weak count does not play any role in deciding the lifetime of the managed object, which is deleted when the reference count reaches zero. However, the control block itself is not deleted until the weak count also reaches zero.

2.4. Deleter

When a shared_ptr is initialized with a pointer, its control block contains a deleter function object (or function pointer), which is invoked to destroy the managed object. If a custom deleter is not provided to the shared_ptr constructor, a default deleter (e.g., std::default_delete ) is used that calls the delete operator.

The deleter is type-erased for two reasons. First, a deleter is an optional argument to a shared_ptr constructor, not a template parameter. Hence, a shared_ptr's type is deleter agnostic. Second, a deleter is a function object (or a function pointer), e.g., function< void(T*) > . This indirection makes shared_ptr independent of the details of how the managed object is deleted. This loose-coupling of shared_ptr with the deleter makes it quite flexible. For instance, in the example below, a vector<shared_ptr<T>> can be in its compilation unit entirely oblivious to the knowledge of how an incomplete type T is deleted:

2.5. Allocator

The control block itself is allocated by an allocator that must satisfy the Allocator requirements. When a custom allocator is not provided, the std::allocator is used that dynamically allocates the control block. The control block keeps a copy of the allocator, which is type-erased like the deleter. There are two ways to use a custom allocator. One is to provide a custom allocator when initializing the shared_ptr with a managed object pointer, as shown below. Note that this shared_ptr constructor also requires a deleter:

Another way to use a custom allocator is to utilize std::allocate_shared that can construct the managed object in-place within a custom allocated control block. Therefore, the std::allocate_shared is like std::make_shared , except that it takes a custom allocator:

3. Conclusion

The std::shared_ptr< T > is a handy yet straightforward utility. But under its simplicity lie extensive details that make it work. Dereferencing a shared_ptr is nearly as fast as a raw pointer, but constructing or copying a shared_ptr is certainly more expensive. Nonetheless, for most applications, this cost is reasonable for automatic memory management.

4. References

std::shared_ptr - cppreference

std::weak_ptr - cppreference

Effective Modern C++ - Scott Meyers

Working with Smart Pointers: unique_ptr, shared_ptr, and weak_ptr

  • First Online: 29 November 2019

Cite this chapter

Book cover

  • Roger Villela 2  

447 Accesses

In this chapter, you’ll learn more about memory management using the smart pointers unique_ptr , shared_ptr , and weak_ptr .

This is a preview of subscription content, log in via an institution to check access.

Access this chapter

  • Available as PDF
  • Read on any device
  • Instant download
  • Own it forever
  • Available as EPUB and PDF
  • Compact, lightweight edition
  • Dispatched in 3 to 5 business days
  • Free shipping worldwide - see info

Tax calculation will be finalised at checkout

Purchases are for personal use only

Institutional subscriptions

Author information

Authors and affiliations.

Sao Paulo, São Paulo, Brazil

Roger Villela

You can also search for this author in PubMed   Google Scholar

Rights and permissions

Reprints and permissions

Copyright information

© 2020 Roger Villela

About this chapter

Villela, R. (2020). Working with Smart Pointers: unique_ptr, shared_ptr, and weak_ptr. In: Introducing Mechanisms and APIs for Memory Management . Apress, Berkeley, CA. https://doi.org/10.1007/978-1-4842-5416-5_4

Download citation

DOI : https://doi.org/10.1007/978-1-4842-5416-5_4

Published : 29 November 2019

Publisher Name : Apress, Berkeley, CA

Print ISBN : 978-1-4842-5415-8

Online ISBN : 978-1-4842-5416-5

eBook Packages : Professional and Applied Computing Apress Access Books Professional and Applied Computing (R0)

Share this chapter

Anyone you share the following link with will be able to read this content:

Sorry, a shareable link is not currently available for this article.

Provided by the Springer Nature SharedIt content-sharing initiative

  • Publish with us

Policies and ethics

  • Find a journal
  • Track your research

MarketSplash

What Is Pointers In C++ And How To Use It

Navigating memory management is a fundamental aspect of C++ programming, and pointers are at the core of this. In this article, we’ll explore the mechanics and usage of pointers in C++, from basic pointer operations to smart pointers, diving into real code examples to cement your understanding.

💡 KEY INSIGHTS

  • Understanding Smart Pointers is essential in modern C++ development, as they provide automatic memory management and prevent common pitfalls like memory leaks and dangling pointers.
  • The RAII (Resource Acquisition Is Initialization) principle is a powerful technique in C++ that simplifies resource management, ensuring timely cleanup and preventing resource leaks.
  • Shared Pointers facilitate efficient memory sharing among multiple objects, reducing memory overhead and enhancing program performance when dealing with shared data structures.
  • Leveraging Unique Pointers can enforce exclusive ownership of resources, preventing accidental resource duplication and ensuring safer and more robust code in C++ applications.

Pointers in C++ are a fundamental concept that can significantly enhance your coding capabilities. They allow for direct memory manipulation, making your programs more efficient and opening doors to advanced programming techniques. While pointers can seem complex at first, a clear understanding of how they work will become an invaluable tool in your programming toolbox.

assign shared pointer to weak pointer

What Is Pointers In C++

Declaring and initializing pointers, pointer arithmetic and operations, pointers and arrays, pointers to functions, memory management with pointers, pointers and classes, common pointer mistakes and how to avoid them, smart pointers in c++, frequently asked questions, pointer initialization, syntax and indirection, pointers and function arguments.

A pointer in C++ is a variable that stores a memory address, serving as a direct link to the value stored at that location. It functions as a gateway, allowing us to read and write to the memory locations it points to.

When declaring a pointer, it’s essential to initialize it , either to another pointer or to nullptr . This ensures it doesn't point to an arbitrary memory location, potentially leading to undefined behavior.

The * symbol serves a dual role; in declarations, it specifies a type is a pointer. When used in expressions, it acts as the dereference operator and accesses the value pointed to.

Pointers are often used as function arguments to allow functions to modify variables from the calling function. This is commonly termed as passing by reference .

Using pointers effectively can make your code more flexible and efficient. However, it is crucial to manage the memory pointers are associated with responsibly to avoid errors and undefined behavior.

Initializing Pointers

Pointer assignment.

To start working with pointers in C++, you first need to declare a pointer variable. This involves specifying the data type that the pointer is going to point to, followed by the asterisk symbol (*) before the pointer name.

Here, we have declared a pointer named 'ptr' that is intended to point to an integer. The data type of 'ptr' is "pointer to int".

After declaration, it’s important to initialize the pointer, either with the address of a variable or with the NULL value. Uninitialized pointers can lead to undefined behavior.

In this example, 'ptr' is a pointer that holds the address of the variable 'num'. The ampersand (&) is used to get the address of 'num'.

Alternatively, pointers can be initialized to NULL , which means they are pointing to no location. This is often a good practice, as it makes it clear that the pointer is not yet pointing to a valid location.

Initializing to 'NULL' is a way to signify that the pointer 'ptr' is not pointing to any memory location initially. In C++11 and later, you can also use 'nullptr' instead of 'NULL'.

Pointers can also be assigned to hold the address of a variable of the appropriate type at any time after their declaration.

Here, 'ptr' is assigned the address of 'num' after its declaration. Again, the ampersand (&) symbol is used to obtain the address of 'num'.

In C++, pointers can be manipulated using a set of specific arithmetic operations, often referred to as pointer arithmetic . These operations enable you to navigate through memory, making pointers a powerful tool for array manipulation and data handling.

Basic Pointer Operations

Subtracting pointers, comparing pointers.

The basic arithmetic operations for pointers include increment ( ++ ), decrement ( -- ), addition ( + ), and subtraction ( - ).

In this example, 'ptr' initially points to the first element of 'arr'. After the increments, it points to the third element (which holds the value '40').

You can subtract two pointers of the same type to find the offset between them. This is useful when you need to calculate the distance between two elements in an array.

Here, 'distance' will hold the value '4', which represents the number of elements between 'start' and 'end'.

Pointers can also be compared using relational operators ( < , > , == , != , <= , >= ). This is useful for checking the positions of two pointers relative to each other.

This condition checks whether 'ptr1' and 'ptr2' are pointing to the same memory location.

It is important to remember that pointer arithmetic is only valid among pointers that point to elements of the same array , or one past the last element of that array. Attempting to perform arithmetic with pointers that don't satisfy this can lead to undefined behavior.

Accessing Array Elements With Pointers

Using pointers to traverse arrays, pointer arithmetic vs array indexing, pointers and multidimensional arrays.

In C++, arrays and pointers are closely related. An array name essentially acts as a constant pointer to the first element of the array. This relationship is fundamental in understanding how to navigate arrays using pointers.

Instead of using array indices, you can use pointer arithmetic to access elements of an array. Incrementing a pointer moves it to the next array element, while decrementing moves it to the previous element.

After this sequence of operations, 'ptr' points to the fourth element of 'arr', which is '4'.

You can use pointers to loop through an array, similar to how you would use an index with a traditional loop.

This loop uses 'ptr' to traverse the array. The loop prints each element of 'arr', outputting "1 2 3 4 5".

While array indexing is more common and usually more readable, pointer arithmetic can be more efficient because it often involves fewer machine instructions.

Both of these lines set the variable (value1 or value2) to the fourth element of 'arr'. They are equivalent operations.

For multidimensional arrays , pointers can also be used to navigate through the elements. In a 2D array, for example, you need a pointer to a pointer to traverse the array.

Here, 'ptr' is a pointer to an array of 3 integers. It points to the first "row" of 'arr'. You can move it to the next row with 'ptr++'.

It is important to use pointers correctly when working with arrays, ensuring you stay within the bounds of the array, to avoid undefined behavior and potential program crashes.

assign shared pointer to weak pointer

More about arrays

Declaring Pointers To Functions

Assigning a function to a pointer, calling a function through a pointer, using function pointers as parameters.

In C++, you can have pointers to functions , allowing functions to be passed as parameters to other functions, stored in data structures, and returned from other functions, much like other data types. This enables a high degree of code reusability and can be used to implement callback functions, table of functions, and more.

To declare a pointer to a function , you need to specify the function’s return type, followed by an asterisk, and then the name of the pointer variable, along with the parameter types of the function.

Here, 'functionPtr' is a pointer to a function that takes an integer and a double as parameters and returns no value (void).

To assign a function to a function pointer , you simply use the name of the function without parentheses.

'exampleFunction' is assigned to the function pointer 'functionPtr'. Note that we are not calling 'exampleFunction'; we are just assigning its address to 'functionPtr'.

Once a function is assigned to a pointer, you can call the function using the pointer in the same way you would call the function directly.

This line of code calls 'exampleFunction' through the 'functionPtr' with arguments '5' and '3.14'. It’s equivalent to calling 'exampleFunction(5, 3.14);' directly.

images

“Learning to write programs stretches your mind, and helps you think better, creates a way of thinking about things that I think is helpful in all domains.

Source: Udacity

Function pointers can also be passed as parameters to other functions , enabling callbacks and higher-order functions.

In this example, 'applyFunction' is a function that takes two parameters, as well as a function pointer 'func'. It calls the function pointed to by 'func' with the provided parameters.

Using pointers to functions can make your code more modular and enable you to use functions as first-class citizens, similar to objects and basic types, thereby facilitating more dynamic and flexible programming designs.

In C++, pointers play a crucial role in memory management . They allow you to have direct control over memory allocation and deallocation. This low-level control is a double-edged sword: it can lead to efficient use of memory, but also to issues like memory leaks and undefined behavior if not used carefully.

Here, 'ptr' is a pointer to an int allocated on the heap. We then store the value '42' in this memory location.

After calling delete , the memory is freed, and 'ptr' should be set to nullptr to avoid undefined behavior.

This code snippet creates a dynamic array of '5' integers and then deallocates the memory.

In this code, if the allocation of a large block of memory fails, a std::bad_alloc exception is caught and an error message is printed.

Here, 'smartPtr' is a std::unique_ptr that takes ownership of a dynamically allocated int . When 'smartPtr' goes out of scope, it automatically deletes the managed memory.

Using smart pointers is a modern and safer approach to memory management in C++, as they help in reducing the risk of memory leaks by ensuring that memory is deallocated when it is no longer needed.

In C++, pointers can be used with classes to create dynamic instances of classes, to implement polymorphic behavior, and to optimize performance by avoiding unnecessary copying of objects. Working with pointers to classes is a fundamental concept, especially when designing complex data structures and systems.

Creating Dynamic Objects

Accessing members via pointers, deleting dynamic objects, pointers and polymorphism, smart pointers and classes.

Using the new operator , you can allocate memory for an instance of a class on the heap, which returns a pointer to the object .

Here, 'objPtr' is a pointer to an object of 'MyClass'. This object is dynamically allocated and initialized with '5'.

To access class members via a pointer to a class object , the arrow operator -> is used.

In this example, we are accessing the 'x' member of the 'MyClass' object pointed to by 'objPtr' and setting it to '10'.

When a class object is created dynamically, it is crucial to release the allocated memory using the delete operator .

After this, the memory used by the object is released, and 'objPtr' is set to nullptr to avoid a dangling pointer.

One of the powerful uses of pointers in C++ is to achieve polymorphism . Using base class pointers , you can point to objects of derived classes.

In this example, 'bPtr' is a pointer of type 'Base', but it is pointing to an object of type 'Derived'. The show function of 'Derived' class is called, demonstrating polymorphism.

Smart pointers , like std::unique_ptr and std::shared_ptr , can also be used with class objects to manage their lifetimes automatically.

Here, 'smartObjPtr' is a std::unique_ptr that takes ownership of a dynamically allocated 'MyClass' object. When 'smartObjPtr' goes out of scope, it automatically deletes the managed object.

Using pointers in conjunction with classes enables advanced programming techniques like polymorphism and dynamic object creation, which are central in object-oriented programming in C++.

Uninitialized pointers can point to random memory locations. Always initialize pointers, either to a valid address or to nullptr .

In the code above, 'p' is an uninitialized pointer, and dereferencing it results in undefined behavior. Initialize 'p' to nullptr or a valid address to avoid this.

In this example, we first check if 'ptr' is not nullptr before attempting to dereference it. This avoids null pointer dereferencing.

Above, we allocate an array of integers dynamically and later release the memory using delete[] . Failing to delete 'arr' would result in a memory leak.

Here, after deleting 'p', we set it to `nullptr'. This avoids a dangling pointer, as 'p' no longer points to an undefined memory location.

In this code, 'ptr' moves outside of 'arr', which is dangerous. Always ensure that pointer arithmetic stays within array bounds.

In this example, 'x' is deleted twice, which is not allowed. Ensure that each new operation has exactly one corresponding delete operation.

assign shared pointer to weak pointer

Common pointer mistakes can lead to serious bugs. Being mindful of these issues and adopting good practices, such as using smart pointers and consistently checking for nullptr before dereferencing, can significantly reduce these risks.

Smart pointers are a modern C++ feature that manage the memory of their underlying objects, helping to avoid common memory management errors. They automatically release memory when no longer needed.

Here, unique_ptr takes ownership of a dynamically allocated int , while shared_ptr is initialized using make_shared . Memory is automatically released when these pointers go out of scope.

std::unique_ptr is a unique pointer that takes ownership of a dynamically allocated object. When the unique_ptr goes out of scope, it deletes its underlying object .

The unique_ptr 'uptr' owns its int object and cannot be copied. When 'uptr' goes out of scope, the memory is released automatically.

std::shared_ptr is a shared pointer that allows multiple shared_ptr instances to share ownership of an object. The object is deleted when the last owning shared_ptr is destroyed .

Here, 'sptr1' and 'sptr2' share ownership of an int . The int is deleted only after both 'sptr1' and 'sptr2' are destroyed.

std::weak_ptr is a weak pointer that observes an object owned by shared_ptr , but doesn't prevent its destruction. It’s useful to break circular references between shared_ptr instances.

Here, 'wk_ptr' is a weak_ptr observing an int owned by 'sh_ptr'. It does not extend the lifetime of the int object.

You can convert a weak_ptr to a shared_ptr to temporarily gain shared ownership of the object.

In this code, 'wk_ptr.lock()' creates a shared_ptr (here 'temp_sptr') from 'wk_ptr'. It’s essential to check for nullptr before using 'temp_sptr' to ensure the object is still alive.

How Do Smart Pointers Avoid Memory Leaks?

Smart pointers automatically delete their underlying objects when those objects are no longer needed. This ensures that the memory occupied by these objects is released, effectively preventing memory leaks that can occur due to manual memory management.

When Should I Use std::unique_ptr ?

Use std::unique_ptr when you want a single owner for a dynamically allocated object. It’s perfect when you want to ensure that only one pointer has the responsibility to delete the object it points to, which happens automatically when the std::unique_ptr goes out of scope.

Can I Copy a std::unique_ptr ?

No, std::unique_ptr instances cannot be copied, because they are designed to have sole ownership of their managed object. However, you can move a std::unique_ptr , transferring ownership from one to another.

When Should I Use std::shared_ptr ?

Use std::shared_ptr when you want multiple pointers to share ownership of a dynamically allocated object. When the last shared_ptr that owns the object is destroyed or reset, the object is automatically deleted.

When and Why Should I Use std::weak_ptr ?

Use std::weak_ptr when you want to observe an object owned by a shared_ptr , but you don’t want to extend the object’s lifetime. This is useful for avoiding circular references that can lead to memory leaks with shared_ptr .

Let’s test your knowledge!

Which of the following is used to declare a pointer in C++?

Continue Learning With These C++ Guides

  • C++ Setlist: What It Is And How To Use It
  • What Is C++ Iterators And How To Use It
  • C++ Deque And Its Efficient Applications
  • What Is Class C++: Functions And Implementation
  • Understanding And Implementing Sort C++ In Your Code

Subscribe to our newsletter

Subscribe to be notified of new content on marketsplash..

IMAGES

  1. Shared Pointer Weak Pointer in c++

    assign shared pointer to weak pointer

  2. C++

    assign shared pointer to weak pointer

  3. Smart Pointers in C++ and How to Use Them

    assign shared pointer to weak pointer

  4. C++ Smart Pointers (2/2)

    assign shared pointer to weak pointer

  5. C++ Smart Pointers Unique/Shared/Weak

    assign shared pointer to weak pointer

  6. Shared Pointer: Understanding shared_ptr

    assign shared pointer to weak pointer

VIDEO

  1. What are Pointers? How to Use Them? and How they can Improve your C++ Programming Skills

  2. C++

  3. [Eng] C++ smart pointers: shared pointer, unique pointers, weak pointers

  4. 09.ASSIGN SUPPORT,PIER LEVEL,DIAPHRAGM,CHECK MODEL IN ETABS

  5. [Arabic] شرح C++ smart pointers: shared pointer, unique pointers, weak pointers

  6. Enable mouse pointer

COMMENTS

  1. c++

    2. Purpose of std::shared_ptr is to release managed object when last shared pointer which points to it is destroyed or reassigned to somewhere else. You created a temporary shared ptr, assgned it to std::weak_ptr and then it is just destroyed at the end of the expression. You need to keep it alive: now rw would not expire at least while shared ...

  2. std::weak_ptr

    std:: weak_ptr. std::weak_ptr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by std::shared_ptr. It must be converted to std::shared_ptr in order to access the referenced object. std::weak_ptr models temporary ownership: when an object needs to be accessed only if it exists, and it may be deleted at ...

  3. std::shared_ptr

    std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer. Several shared_ptr objects may own the same object. The object is destroyed and its memory deallocated when either of the following happens: the last remaining shared_ptr owning the object is destroyed; ; the last remaining shared_ptr owning the object is assigned another pointer via operator= or ...

  4. weak_ptr in C++

    weak_ptr in C++. The weak_ptr is one of the smart pointers that provide the capability of a pointer with some reduced risks as compared to the raw pointer. The weak_ptr, just like shared_ptr has the capability to point to the resource owned by another shared_ptr but without owning it. In other words, they are able to create a non-owning ...

  5. How to: Create and use weak_ptr instances

    A weak_ptr itself does not participate in the reference counting, and therefore, it cannot prevent the reference count from going to zero. However, you can use a weak_ptr to try to obtain a new copy of the shared_ptr with which it was initialized. If the memory has already been deleted, the weak_ptr 's bool operator returns false.

  6. Mastering Weak Pointers in C++: Essential Guide

    Commonly, weak pointers are initialized from a shared pointer: #include <memory> int main() { auto SharedPtr { std::make_shared<int>(42) }; std::weak_ptr<int> WeakPtr{SharedPtr}; } When creating a weak pointer from a shared pointer, the type within the <> can be deduced from the equivalent type of the shared pointer - int, in this case.

  7. shared_ptr in C++

    shared_ptr in C++. std::shared_ptr is one of the smart pointers introduced in C++11. Unlike a simple pointer, it has an associated control block that keeps track of the reference count for the managed object. This reference count is shared among all the copies of the shared_ptr instances pointing to the same object, ensuring proper memory ...

  8. std::weak_ptr

    Since C++11. std::weak_ptr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by std::shared_ptr . It must be converted to std::shared_ptr in order to access the referenced object. std::weak_ptr models temporary ownership: when an object needs to be accessed only if it exists, and it may be deleted at any ...

  9. C++ Smart Pointers (Shared, Unique and Weak Pointers)

    The Weak Pointer class is a sort of extension, or companion of the Shared Pointer. It does not manage the life time of the object that it points to, unlike the other two smart pointers. It instead, points to an object that is managed by a shared pointer, but unlike a regular shared pointer, it does not increase the reference count.

  10. Mastering Smart Pointers in C++. unique_ptr, shared_ptr, and weak_ptr

    std::weak_ptr is used in conjunction with std::shared_ptr. It holds a non-owning reference to a shared object, meaning it does not contribute to the reference count.

  11. Understanding Shared Pointers in C++: A Comprehensive Guide

    The std::make_shared() function creates an object of the type specified between the < and > tokens, allocated in dynamic memory. It returns a std::shared_ptr of that same type.. For example, std::make_shared<Character>() will create a Character in dynamic memory, and return a std::shared_ptr<Character> that points to it. Any function arguments passed to std::make_shared() are forwarded to the ...

  12. c++

    It was mentioned that there are tr1::shared_ptr and tr1::weak_ptr act like built-in pointers, but they keep track of how many tr1::shared_ptrs point to an object. This is known as reference counting. This works well in preventing resource leaks in acyclic data structures, but if two or more objects contain tr1::shared_ptrs such that a cycle is ...

  13. How to: Create and use shared_ptr instances

    In this article. The shared_ptr type is a smart pointer in the C++ standard library that is designed for scenarios in which more than one owner needs to manage the lifetime of an object. After you initialize a shared_ptr you can copy it, pass it by value in function arguments, and assign it to other shared_ptr instances. All the instances point to the same object, and share access to one ...

  14. C++

    An std::weak_ptr is a non-owning smart pointer that maintains a weak reference to an std::shared_ptr managed object. Multiple shared_ptr instances can share the ownership of a managed object. The managed object is deleted when the last owning shared_ptr is destroyed. Therefore, a shared_ptr is a strong reference to a managed object.

  15. C++

    2.3. Weak Counter. A control block also keeps the count of weak_ptr associated with it in a weak counter. An std::weak_ptr is a smart pointer that serves as a weak reference to an std::shared_ptr managed object. When a weak_ptr is created from a shared_ptr, it refers to the same control block but does not share the ownership of the managed object.It is not possible to directly access the ...

  16. Creating shared_ptr from raw pointer in C++ · Siyuan's Blog

    The reason why it can keep track is because std::shared_ptr has a pointer to a struct that stores the reference count besides the pointer to the actual object. Therefore, when you create a std::shared_ptr from another one , it will increment the count properly (the two std::shared_ptr s point to the same struct).

  17. C++: Inner workings of shared pointers

    SP2 - Value: 10, Ref count: 2. SP1 - Value: 10, Ref count: 1. When a shared pointer is copied, all instances are pointing to the same data in the heap, and an internal reference count is updated ...

  18. Working with Smart Pointers: unique_ptr, shared_ptr, and weak_ptr

    Chapter 3 gave you an overview of the composite type pointer, introducing some concepts and presenting a practical use of a composite type pointer. In Chapter 3 you also started to work with raw pointers and with smart pointers, specifically with unique_ptr.. In this chapter, you will learn about more specific features of unique_ptr and also learn about shared_ptr and weak_ptr.

  19. What Is Pointers In C++ And How To Use It

    Assigning A Function To A Pointer. To assign a function to a function pointer, you simply use the name of the function without parentheses. void exampleFunction(int a, double b) { // Function implementation } functionPtr = exampleFunction; // Assigns the function to the pointer ... make_shared<int>(30); std::weak_ptr<int> wk_ptr = sh_ptr ...

  20. std::weak_ptr assignment with std::make_shared

    std::weak_ptr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by std::shared_ptr... If the original std::shared_ptr is destroyed at this time, the object's lifetime is extended until the temporary std::shared_ptr is destroyed as well. edited May 31, 2017 at 16:52. Caribou.

  21. Is it safe/bad practice to create shared pointers from a weak pointer

    All classes get shared pointers. good: No need to create shared objects from weak ones. bad: The shared object inside the class needed to be explicitely deleted (like with a call of a method for example Node::destroySelfReference() which can easily be forgotten. Otherwise the object could live forever with a reference to itself.