std::shared_ptr
std::shared_ptr
is one of the most commonly used smart pointers in C++. It is a reference-counted smart pointer, meaning it keeps track of how many std::shared_ptr
instances point to the same resource. The resource is automatically freed when the last std::shared_ptr
pointing to it is destroyed or reset. This makes std::shared_ptr
particularly useful when multiple parts of a program need to share ownership of a resource.
std::shared_ptr
std::shared_ptr
instances can own the same resource. The resource will only be destroyed when the last std::shared_ptr
owning it is destroyed.std::shared_ptr
internally maintains a reference count to keep track of how many shared_ptr
instances share the same resource.std::shared_ptr
can be safely used in multi-threaded environments.#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() { std::cout << "MyClass Constructor" << std::endl; }
~MyClass() { std::cout << "MyClass Destructor" << std::endl; }
void sayHello() const { std::cout << "Hello from MyClass" << std::endl; }
};
int main() {
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(); // Create a shared_ptr
{
std::shared_ptr<MyClass> ptr2 = ptr1; // Share ownership with ptr2
ptr2->sayHello(); // Use the object
std::cout << "Reference count: " << ptr1.use_count() << std::endl; // Outputs: 2
}
// ptr2 goes out of scope, reference count decreases
std::cout << "Reference count: " << ptr1.use_count() << std::endl; // Outputs: 1
return 0;
}
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
creates a std::shared_ptr
that manages a new MyClass
object.ptr2 = ptr1;
creates another std::shared_ptr
pointing to the same object, increasing the reference count.ptr1.use_count()
returns the number of shared_ptr
instances owning the resource.ptr2
goes out of scope, the reference count decreases. The object is only destroyed when the reference count drops to zero (i.e., when the last std::shared_ptr
is destroyed or reset).std::shared_ptr
can be copied and assigned, unlike std::unique_ptr.
Copying a std::shared_ptr
increases the reference count, while assignment replaces the ownership of the shared_ptr
.
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() { std::cout << "MyClass Constructor" << std::endl; }
~MyClass() { std::cout << "MyClass Destructor" << std::endl; }
};
int main() {
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
std::shared_ptr<MyClass> ptr2 = ptr1; // Copy ptr1, reference count increases
std::cout << "Reference count after copying: " << ptr1.use_count() << std::endl; // Outputs: 2
std::shared_ptr<MyClass> ptr3;
ptr3 = ptr1; // Assign ptr1 to ptr3, reference count remains the same
std::cout << "Reference count after assignment: " << ptr1.use_count() << std::endl; // Outputs: 3
return 0;
}
ptr1
to ptr2
increases the reference count to 2.ptr1
to ptr3
increases the reference count to 3.std::shared_ptr
allows you to specify a custom deleter, which is a function or function object that is called when the last std::shared_ptr
is destroyed and the resource is freed. This is useful for managing resources that require special cleanup, such as closing a file or freeing memory allocated in a non-standard way.
std::shared_ptr
with a Custom Deleter#include <iostream>
#include <memory>
#include <cstdio> // For FILE*
struct FileDeleter {
void operator()(FILE* fp) const {
if (fp) {
std::cout << "Closing file" << std::endl;
std::fclose(fp);
}
}
};
int main() {
std::shared_ptr<FILE> filePtr(std::fopen("example.txt", "w"), FileDeleter());
if (filePtr) {
std::fprintf(filePtr.get(), "Hello, file!\n");
}
// filePtr goes out of scope, and FileDeleter is invoked to close the file
return 0;
}
FileDeleter
is a custom deleter that closes the file when the last std::shared_ptr
is destroyed.std::shared_ptr<FILE> filePtr(std::fopen("example.txt", "w"), FileDeleter());
creates a shared_ptr
to manage a FILE *
resource with the custom deleter.filePtr
goes out of scope, the custom deleter is called, closing the file.One potential issue with std::shared_ptr
is circular references, where two or more shared_ptr
instances reference each other. This can lead to memory leaks because the reference count never reaches zero, preventing the objects from being destroyed. To avoid this, std::weak_ptr
can be used to break the cycle.
#include <iostream>
#include <memory>
class Node;
class Node {
public:
std::shared_ptr<Node> next;
std::shared_ptr<Node> prev;
Node() { std::cout << "Node Constructor" << std::endl; }
~Node() { std::cout << "Node Destructor" << std::endl; }
};
int main() {
std::shared_ptr<Node> node1 = std::make_shared<Node>();
std::shared_ptr<Node> node2 = std::make_shared<Node>();
node1->next = node2; // node1 points to node2
node2->prev = node1; // node2 points back to node1
// This creates a circular reference, preventing both nodes from being destroyed
return 0;
}
node1
and node2
create a circular reference. Both nodes point to each other with shared_ptr
.std::shared_ptr
is a reference-counted smart pointer that allows multiple ownership of a dynamically allocated resource.std::shared_ptr
is destroyed.std::shared_ptr
supports custom deleters for handling special cleanup requirements.std::weak_ptr
to break these cycles.std::shared_ptr
is a powerful tool in modern C++ for managing shared ownership of resources, ensuring that they are automatically cleaned up when no longer needed, while also providing flexibility through custom deleters.