智能指针share_ptr/weak_ptr
文章目录
A、初步认识share_ptr
1、share_ptr的基本用法
#include <iostream>
#include <memory>
#include <vector>
// 定义一个简单的类,用于演示
class MyClass {
public:
MyClass(const std::string& name) : name(name) {
std::cout << "MyClass constructor: " << name << std::endl;
}
~MyClass() {
std::cout << "MyClass destructor: " << name << std::endl;
}
// 用于演示循环引用问题
std::shared_ptr<MyClass> friendClass;
void greet() {
std::cout << "Hello, I am " << name << std::endl;
}
private:
std::string name;
};
// 使用 shared_ptr 和 weak_ptr
void demo_shared_weak_ptr() {
std::cout << "=== demo_shared_weak_ptr ===" << std::endl;
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>("Shared1");
std::shared_ptr<MyClass> ptr2 = ptr1;
ptr1->greet();
ptr2->greet();
std::cout << "Use count: " << ptr1.use_count() << std::endl;
}
int main() {
demo_shared_weak_ptr();
return 0;
}
2、share_ptr的基本原理构造和析构及使用原理
3、循环引用是如何产生的及如何避免
UML类图
重新实现
#include <iostream>
#include <mutex>
// Forward declaration
template <typename T>
class SharedPtr;
template <typename T>
class SharedCounter {
public:
SharedCounter(T* ptr) : data(ptr), uses(1), weaks(1) {}
~SharedCounter() {}
void increaseUses() {
std::lock_guard<std::mutex> lock(mtx);
++uses;
}
void decreaseUses() {
{
std::lock_guard<std::mutex> lock(mtx);
uses--;
}
if (uses == 0) {
delete data;
data = nullptr;
decreaseWeaks();
}
}
void increaseWeaks() {
std::lock_guard<std::mutex> lock(mtx);
++weaks;
}
void decreaseWeaks() {
if (--weaks == 0) {
delete this;
}
}
int usesCount() const {
return uses;
}
int weaksCount() const {
return weaks;
}
private:
T* data;
int uses;
int weaks;
mutable std::mutex mtx;
};
template <typename T>
class SharedPtr {
public:
SharedPtr() : counter(nullptr), data(nullptr) {}
explicit SharedPtr(T* ptr) : counter(new SharedCounter<T>(ptr)), data(ptr) {}
SharedPtr(const SharedPtr& other) : counter(other.counter), data(other.data) {
if (counter) {
counter->increaseUses();
}
}
SharedPtr& operator=(const SharedPtr& other) {
if (this == &other) {
return *this;
}
if (counter) {
counter->decreaseUses();
}
counter = other.counter;
data = other.data;
if (counter) {
counter->increaseUses();
}
return *this;
}
~SharedPtr() {
if (counter) {
counter->decreaseUses();
}
}
T& operator*() {
return *data;
}
T* operator->() {
return data;
}
private:
SharedCounter<T>* counter;
T* data;
};
// Example usage
int main() {
SharedPtr<int> p1(new int(42));
SharedPtr<int> p2 = p1; // Copy constructor increases the counter
std::cout << *p1 << std::endl; // Output should be 42
std::cout << *p2 << std::endl; // Output should be 42
return 0;
}
B、进一步认识share_ptr
enable_shared_from_this 作用、目的、原理
//错误例子1
class A
{
public:
A() :data(new int)
{
cout << "A()" << endl;
}
~A()
{
cout << "~A()" << endl;
delete data;
data = nullptr;
}
private:
int* data;
};
int main()
{
A* p = new A(); // 裸指针指向堆上的对象
shared_ptr<A> ptr1(p);// 用shared_ptr智能指针管理指针p指向的对象
shared_ptr<A> ptr2(p);// 用shared_ptr智能指针管理指针p指向的对象
// 下面两次打印都是1,因此同一个new A()被析构两次,逻辑错误
cout << ptr1.use_count() << endl;
cout << ptr2.use_count() << endl;
return 0;
}
//错误例子2,调式发现问题
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass(const std::string& name) : name(name) {
std::cout << "MyClass constructor: " << name << std::endl;
}
~MyClass() {
std::cout << "MyClass destructor: " << name << std::endl;
}
void greet() {
std::cout << "Hello, I am " << name << std::endl;
}
std::shared_ptr<MyClass> getShared() {
return std::shared_ptr<MyClass>(this);
}
private:
std::string name;
};
int main() {
std::shared_ptr<MyClass> obj1 = std::make_shared<MyClass>("Object1");
obj1->greet(); // Output: Hello, I am Object1
// 获取新的shared_ptr实例
std::shared_ptr<MyClass> obj2 = obj1->getShared();
obj2->greet(); // Output: Hello, I am Object1
std::cout << "Use count of obj1: " << obj1.use_count() << std::endl; // Output: Use count of obj1: 2
std::cout << "Use count of obj2: " << obj2.use_count() << std::endl; // Output: Use count of obj2: 2
return 0;
}
//若使用拷贝构造函数就不会出现释放两次的现象
shared_ptr<int> ptr1(new int);
shared_ptr<int> ptr2(ptr1);
cout<<ptr1.use_count()<<endl;
cout<<ptr2.use_count()<<endl;
//重点
//正确
shared_ptr<int> ptr1(new int);
shared_ptr<int> ptr2(ptr1);
cout<<ptr1.use_count()<<endl;
cout<<ptr2.use_count()<<endl;
//错误
int *p = new int;
shared_ptr<int> ptr1(p);
shared_ptr<int> ptr2(p);
cout<<ptr1.use_count()<<endl;
cout<<ptr2.use_count()<<endl;
-
shared_ptr 会增加资源的引用计数,常用于管理对象的生命周期。
-
weak_ptr 不会增加资源的引用计数,常作为观察者用来判断对象是否存活。
-
使用 shared_ptr 的普通拷贝构造函数会产生额外的引用计数对象,可能导致对象多次析构。使用 shared_ptr 的拷贝构造函数则只影响同一资源的同一引用计数的增减。
-
当需要返回指向当前对象的 shared_ptr 时,优先使用 enable_shared_from_this 机制