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;
};
存在两个注意事项:
-
关于int,成员变量的引用计数必须是int*。不可以直接是int,不然没有引用计数的作用。
-
关于是否可以声明为静态成员。不可以,否则每一个相同类型的对象都共享该计数。
其他
-
共享指针总体的使用来说是不线程安全的(构造和析构时才会改变引用计数,但是在访问资源时是不安全的)。可以对引用计数改变时加锁,或者将+或-操作改变为原子操作。
-
循环引用。需要通过weak_ptr进行解决。
cpp
class Test
{
private:
std::shared_ptr<Test> m_friend; // 为了避免循环引用,改为weak_ptr即可
}
- 不可以将shared_ptr转换为unique_ptr。 unique_ptr可以转换为shared_ptr,通过std::move。