智能指针学习笔记

unique_ptr

依靠独占权方式控制。

使用方法如下:

cpp 复制代码
#include <iostream>
#include <memory>
 
class TestA
{
    public:
        TestA(int n): member(n){};
 
        void show() {
            std::cout << "init class, n: " << member << std::endl;
        }
    
    private:
        int member;
};
 
 
void pass_by_value(std::unique_ptr<TestA> a) 
{
    std::cout << "pass by value \n";
    a->show();
}
 
void print_by_ref(std::unique_ptr<TestA> &a)
{
    std::cout << "print by ref \n";
    a->show();
    a.reset();      // 清空指针
}
 
void print_by_ref_const(const std::unique_ptr<TestA> &a)
{
    std::cout << "print by ref \n";
    a->show();
    // a.reset();   // const 引用,不可以修改值
}
 
std::unique_ptr<TestA> return_by_value()
{
    std::cout << "return by value function \n";
    std::unique_ptr<TestA> local = std::make_unique<TestA>(6);
    return local;
}
 
int main()
{
    // 构造方式1
    TestA *a_ptr = new TestA(1);
    std::unique_ptr<TestA> a_unique_ptr{a_ptr};
    a_unique_ptr->show();
 
    // 构造方式2
    std::unique_ptr<TestA> unique_ptr_02{new TestA(2)};
    unique_ptr_02->show();
 
    // 构造方式3
    std::unique_ptr<TestA> unique_ptr_03 = std::make_unique<TestA>(3);
    unique_ptr_03->show();
 
    // 函数传递值
    std::unique_ptr<TestA> unique_pass_by_value = std::make_unique<TestA>(4);
    pass_by_value(std::move(unique_pass_by_value));     // 转换为右值
 
    // 传递引用
    std::unique_ptr<TestA> unique_pass_by_ref = std::make_unique<TestA>(5);
    print_by_ref(unique_pass_by_ref);
 
    // 函数返回值
    std::unique_ptr<TestA> return_by_value_ptr{std::move(return_by_value())};
    return_by_value_ptr->show();
 
    return 0;
}

模拟实现原理:

cpp 复制代码
	template<class T>
	class unique_ptr
	{
	public:
		// RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源
		// 保存资源
		unique_ptr(T* ptr)
			:_ptr(ptr)
		{}
		// 释放资源
		~unique_ptr()
		{
			delete _ptr;
		}

		unique_ptr(const unique_ptr<T>& up) = delete;
		unique_ptr<T>& operator=(const unique_ptr<T>& up) = delete;

		// 像指针一样
		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return return _ptr;
		}

		T& operator[](size_t pos)
		{
			return _ptr[pos];
		}
	private:
		T* _ptr;
	};

shared_ptr

使用方式如下:

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>
 
class TestA
{
    public:
        TestA(int n, std::string name): member(n), m_name(name){};
 
        void show() {
            std::cout << "Init class, id: " << member << " name: " << m_name << std::endl;
        }
 
        void update_name(std::string name) {
            m_name = name;
        }
    
    private:
        int member;
        std::string m_name;
};
 
 
void pass_by_value(std::shared_ptr<TestA> a)
{
    std::cout << "------------------------------------------------------------- \n";
    std::cout << "pass by value function \n";
    a->show();
    std::cout << "use count: " << a.use_count() << std::endl;
    std::cout << "------------------------------------------------------------- \n";
}
 
 
void pass_by_ref(std::shared_ptr<TestA> &a)
{
    std::cout << "------------------------------------------------------------- \n";
    std::cout << "pass by ref function \n";
    a->show();
    std::cout << "use count: " << a.use_count() << std::endl;
    std::cout << "------------------------------------------------------------- \n";
}
 
std::shared_ptr<TestA> get_share_ptr()
{
    std::shared_ptr<TestA> local = std::make_shared<TestA>(10, "local");
    return local;
}
 
int main()
{
    // 构建方式1
    std::shared_ptr<TestA> ptr1 = std::make_shared<TestA>(1, "bobo");
    ptr1->show();
 
    // 查看引用计数
    std::cout << "use count: " << ptr1.use_count() << std::endl;
 
    // 赋值
    std::shared_ptr<TestA> ptr2 = ptr1;
    auto ptr3 = ptr1;
    
    std::cout << "ptr1 use count: " << ptr1.use_count() << std::endl;
    std::cout << "ptr2 use count: " << ptr2.use_count() << std::endl;
    std::cout << "ptr3 use count: " << ptr3.use_count() << std::endl;
 
    // 删除某一个指针观察引用计数
    ptr2 = nullptr;      // ptr2.reset();
    
    std::cout << "ptr1 use count: " << ptr1.use_count() << std::endl;
    std::cout << "ptr3 use count: " << ptr3.use_count() << std::endl;
 
    // 因为共享某一块内存,可以观察值
    std::cout << "------------------------------------------------------------- \n";
    ptr1->update_name("tom");
    ptr1->show();
    ptr3->show();
 
    std::cout << "------------------------------------------------------------- \n";
    pass_by_value(ptr1);
    std::cout << "ptr1 use count: " << ptr1.use_count() << std::endl;
    std::cout << "ptr3 use count: " << ptr3.use_count() << std::endl;
 
    std::cout << "------------------------------------------------------------- \n";
    pass_by_ref(ptr1);
    std::cout << "ptr1 use count: " << ptr1.use_count() << std::endl;
    std::cout << "ptr3 use count: " << ptr3.use_count() << std::endl;
 
    std::cout << "------------------------------------------------------------- \n";
    std::shared_ptr<TestA> ptr4 = get_share_ptr();
    std::cout << "ptr4 use count: " << ptr4.use_count() << std::endl;
 
    std::cout << "Finished! \n";
    return 0;
}

模拟实现原理:

cpp 复制代码
	template<class T>
	class shared_ptr
	{
	public:
		// RAII
		// 保存资源
		shared_ptr(T* ptr)
			:_ptr(ptr)
			, _pcount(new int(1))
		{}

		// 释放资源
		~shared_ptr()
		{
			Release();
		}

		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			, _pcount(sp._pcount)
		{
			++(*_pcount);
		}

		void Release()
		{
			if (--(*_pcount) == 0)
			{
				delete _pcount;
				delete _ptr;
			}
		}
        
        //sp1 = sp1;
        //sp1 = sp2;//sp2如果是sp1的拷贝呢?
		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			if (_ptr != sp._ptr)//资源地址不一样
			{
				Release();
				_pcount = sp._pcount;
				_ptr = sp._ptr;
				++(*_pcount);
			}

			return *this;
		}
        
        int use_count()
		{
			return *_pcount;
		}

		// 像指针一样
		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		T& operator[](size_t pos)
		{
			return _ptr[pos];
		}
	private:
		T* _ptr;
		int* _pcount;
	};

存在两个注意事项:

  1. 关于int,成员变量的引用计数必须是int*。不可以直接是int,不然没有引用计数的作用。

  2. 关于是否可以声明为静态成员。不可以,否则每一个相同类型的对象都共享该计数。

其他

  1. 共享指针总体的使用来说是不线程安全的(构造和析构时才会改变引用计数,但是在访问资源时是不安全的)。可以对引用计数改变时加锁,或者将+或-操作改变为原子操作。

  2. 循环引用。需要通过weak_ptr进行解决。

cpp 复制代码
class Test 
{
    private:
        std::shared_ptr<Test> m_friend;     // 为了避免循环引用,改为weak_ptr即可
}
  1. 不可以将shared_ptr转换为unique_ptr。 unique_ptr可以转换为shared_ptr,通过std::move。

参考资料:【C++11】智能指针_c++智能指针-CSDN博客

相关推荐
黑不拉几的小白兔7 分钟前
PTA部分题目C++重练
开发语言·c++·算法
迷迭所归处8 分钟前
动态规划 —— dp 问题-买卖股票的最佳时机IV
算法·动态规划
写bug的小屁孩8 分钟前
websocket身份验证
开发语言·网络·c++·qt·websocket·网络协议·qt6.3
chordful29 分钟前
Leetcode热题100-32 最长有效括号
c++·算法·leetcode·动态规划
_OLi_37 分钟前
力扣 LeetCode 459. 重复的子字符串(Day4:字符串)
算法·leetcode·职场和发展·kmp
材料苦逼不会梦到计算机白富美40 分钟前
线性DP 区间DP C++
开发语言·c++·动态规划
java小吕布42 分钟前
Java Lambda表达式详解:函数式编程的简洁之道
java·开发语言
Romanticroom44 分钟前
计算机23级数据结构上机实验(第3-4周)
数据结构·算法
白藏y1 小时前
数据结构——归并排序
数据结构·算法·排序算法
sukalot1 小时前
windows C#-查询表达式基础(一)
开发语言·c#