[STL解析]智能指针share_ptr/weak_ptr

智能指针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 机制

share_ptr的所有构造函数

share_ptr的其他函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值