在学习《Effective Modern C++》的过程中学到了智能指针,智能指针对于现代C++编程十分重要,为了加深理解,参考了网上很多智能指针的实现,简单实现了智能指针的基本功能,可能存在问题,欢迎大家指正。
unique_ptr:每个 unique_ptr 指针都独自拥有对其所指堆内存空间的所有权。
成员函数名 | 功 能 |
operator*() | 获取当前 unique_ptr 指针指向的数据。 |
operator->() | 重载 -> 号,当智能指针指向的数据类型为自定义的结构体时,通过 -> 运算符可以获取其内部的指定成员。 |
operator =() | 重载了 = 赋值号,从而可以将 nullptr 或者一个右值 unique_ptr 指针直接赋值给当前同类型的 unique_ptr 指针。 |
operator []() | 重载了 [] 运算符,当 unique_ptr 指针指向一个数组时,可以直接通过 [] 获取指定下标位置处的数据。 |
get() | 获取当前 unique_ptr 指针内部包含的普通指针。 |
get_deleter() | 获取当前 unique_ptr 指针释放堆内存空间所用的规则。 |
operator bool() | unique_ptr 指针可直接作为 if 语句的判断条件,以判断该指针是否为空,如果为空,则为 false;反之为 true。 |
release() | 释放当前 unique_ptr 指针对所指堆内存的所有权,但该存储空间并不会被销毁。 |
reset(p) | 其中 p 表示一个普通指针,如果 p 为 nullptr,则当前 unique_ptr 也变成空指针;反之,则该函数会释放当前 unique_ptr 指针指向的堆内存(如果有),然后获取 p 所指堆内存的所有权(p 为 nullptr)。 |
swap(x) | 交换当前 unique_ptr 指针和同类型的 x 指针。 |
shared_ptr:多个指针可以共享同一块内存,底层采用引用计数,当计数为0时,空间被释放
成员方法名 | 功 能 |
operator=() | 重载赋值号,使得同一类型的 shared_ptr 智能指针可以相互赋值。 |
operator*() | 重载 * 号,获取当前 shared_ptr 智能指针对象指向的数据。 |
operator->() | 重载 -> 号,当智能指针指向的数据类型为自定义的结构体时,通过 -> 运算符可以获取其内部的指定成员。 |
swap() | 交换 2 个相同类型 shared_ptr 智能指针的内容。 |
reset() | 当函数没有实参时,该函数会使当前 shared_ptr 所指堆内存的引用计数减 1,同时将当前对象重置为一个空指针;当为函数传递一个新申请的堆内存时,则调用该函数的 shared_ptr 对象会获得该存储空间的所有权,并且引用计数的初始值为 1。 |
get() | 获得 shared_ptr 对象内部包含的普通指针。 |
use_count() | 返回同当前 shared_ptr 对象(包括它)指向相同的所有 shared_ptr 对象的数量。 |
unique() | 判断当前 shared_ptr 对象指向的堆内存,是否不再有其它 shared_ptr 对象再指向它。 |
operator bool() | 判断当前 shared_ptr 对象是否为空智能指针,如果是空指针,返回 false;反之,返回 true。 |
weak_ptr:shared_ptr存在循环引用的问题,通过weak_ptr来解决;除此之外,应用场景还包括缓存和观察者列表
成员方法 | 功 能 |
operator=() | 重载 = 赋值运算符,是的 weak_ptr 指针可以直接被 weak_ptr 或者 shared_ptr 类型指针赋值。 |
swap(x) | 其中 x 表示一个同类型的 weak_ptr 类型指针,该函数可以互换 2 个同类型 weak_ptr 指针的内容。 |
reset() | 将当前 weak_ptr 指针置为空指针。 |
use_count() | 查看指向和当前 weak_ptr 指针相同的 shared_ptr 指针的数量。 |
expired() | 判断当前 weak_ptr 指针为否过期(指针为空,或者指向的堆内存已经被释放)。 |
lock() | 如果当前 weak_ptr 已经过期,则该函数会返回一个空的 shared_ptr 指针;反之,该函数返回一个和当前 weak_ptr 指向相同的 shared_ptr 指针。 |
具体实现:
#pragma once
#include <iostream>
namespace Myptr {
/ unique_ptr //
// 默认删除器
template <typename T>
struct PointerDeleter {
void operator()(const T* ptr) {
if (ptr) {
delete ptr;
ptr = nullptr;
}
}
};
template<class T, typename Deleter = PointerDeleter<T> >
class unique_ptr {
private:
// 原始指针
T* ptr;
public:
// 构造函数
explicit unique_ptr() : ptr(nullptr) {}
explicit unique_ptr(T* _ptr) : ptr(_ptr) {}
// 移动构造函数
unique_ptr(unique_ptr&& p) noexcept;
// 移动赋值函数
unique_ptr& operator=(unique_ptr&& p) noexcept;
// 析构函数
~unique_ptr() {
Deleter()(ptr);
std::cout << "unique ptr destroy!" << std::endl;
};
// 重载运算符
T& operator*() const noexcept { return *ptr; }
T* operator->() const noexcept { return ptr; }
explicit operator bool() const noexcept { return ptr != nullptr; };
// 返回原始指针
T* get() const noexcept { return ptr; }
// 返回指针,释放所有权
T* release() noexcept {
T* pointer = ptr;
ptr = nullptr;
return pointer;
}
// 替换被管理的对象
void reset(T* _ptr = nullptr) noexcept {
if (ptr != _ptr) {
Deleter()(ptr);
ptr = _ptr;
}
}
// 交换被管理的对象
void swap(unique_ptr& p) noexcept {
std::swap(ptr, p.ptr);
}
// 不允许使用拷贝相关
unique_ptr(const unique_ptr& p) = delete;
unique_ptr& operator=(const unique_ptr& p) = delete;
};
template <typename T, typename Deleter>
unique_ptr<T, Deleter>::unique_ptr(unique_ptr&& p) noexcept : ptr(p.ptr) {
p.ptr = nullptr;
}
template <typename T, typename Deleter>
unique_ptr<T, Deleter>& unique_ptr<T, Deleter>::operator=(unique_ptr&& p) noexcept {
std::swap(ptr, p.ptr);
return *this;
}
// shared_ptr //
template<typename T> class weak_ptr; // 声明weak_ptr为模板类
template<typename T, class Deleter > class shared_ptr; // 声明shared_ptr为模板类
template<class T, class Deleter = PointerDeleter<T> >
class shared_ptr {
friend class weak_ptr<T>;
private:
T* m_ptr = nullptr;
size_t* ref_count = nullptr;
public:
// 默认构造函数
explicit shared_ptr(): m_ptr(nullptr), ref_count(new size_t(0)) {}
explicit shared_ptr(T* ptr): m_ptr(ptr), ref_count(new size_t(1)) {}
// 拷贝构造函数和拷贝复制函数
shared_ptr(const shared_ptr& p) {
m_ptr = p.m_ptr;
ref_count = p.ref_count;
if (ref_count != nullptr) {
(*ref_count)++;
}
}
shared_ptr(const weak_ptr<T>& wp) {
m_ptr = wp.m_ptr;
ref_count = wp.ref_count;
(*ref_count)++;
}
shared_ptr& operator=(const shared_ptr& p) {
if (p.m_ptr == m_ptr) {
return *this;
}
//先处理原有的指针和引用计数
if (ref_count != nullptr)
{
(*ref_count)--;
if (*ref_count == 0)
{
delete m_ptr;
delete ref_count;
}
}
//再处理赋值
m_ptr = p.m_ptr;
ref_count = p.ref_count;
if (ref_count != nullptr)
{
(*ref_count)++;
}
return *this;
}
// 移动构造函数和移动赋值函数
shared_ptr(shared_ptr&& dying_obj) noexcept : m_ptr(nullptr), ref_count(nullptr) {
//初始化后交换指针和引用计数, 等于清除了原shared_ptr的内容
dying_obj.swap(*this);
}
shared_ptr& operator=(shared_ptr&& dying_obj) noexcept {
//my_shared_ptr(std::move(dying_obj))用移动构造函数创建出一个新的shared_ptr(此时dying_obj的内容被清除了)
//再和this交换指针和引用计数
//因为this被交换到了当前的临时创建的my_shared_ptr里,this的引用计数-1
shared_ptr(std::move(dying_obj)).swap(*this);
//dying_obj.swap(*this);
return *this;
}
// 析构函数
~shared_ptr() {
std::cout << "delete" << std::endl;
if (ref_count == nullptr)
{
return;
}
(*ref_count)--;
if (*ref_count > 0)
{
return;
}
if (m_ptr != nullptr)
{
Deleter()(m_ptr);
}
delete ref_count;
}
// 操作符重载
T& operator*() const { return *m_ptr; }
T* operator->() const { return m_ptr; }
explicit operator bool() { return m_ptr != nullptr; }
// 工具函数
void swap(shared_ptr& other) {
std::swap(m_ptr, other.m_ptr);
std::swap(ref_count, other.ref_count);
}
T* get() const { return m_ptr; }
size_t use_count() const {
return ref_count != nullptr ? *ref_count : 0;
}
bool unique() { return *ref_count == 1; }
void reset(T* ptr = nullptr) {
if (ptr == nullptr) {
(*ref_count)--;
m_ptr = nullptr;
ref_count = nullptr;
}
else {
shared_ptr<T, Deleter>().swap(*this);
m_ptr = ptr;
ref_count = new size_t(1);
}
}
};
/ weak_ptr
template<class T>
class weak_ptr {
friend class shared_ptr<T>;
private:
T* m_ptr;
size_t* ref_count;
public:
weak_ptr() noexcept : m_ptr(nullptr), ref_count(new size_t(0)) {}
weak_ptr(T* ptr) noexcept : m_ptr(ptr), ref_count(new size_t(1)) {}
weak_ptr(const weak_ptr& wp): m_ptr(wp.m_ptr), ref_count(wp.ref_count) {}
weak_ptr(const shared_ptr<T>& sp): m_ptr(sp.m_ptr), ref_count(sp.ref_count) {}
weak_ptr& operator=(const weak_ptr& wp) {
if (*this != wp) {
m_ptr = wp.m_ptr;
ref_count = wp.ref_count;
}
return *this;
}
weak_ptr& operator=(const shared_ptr<T>& sp) {
m_ptr = sp.m_ptr;
ref_count = sp.ref_count;
return *this;
}
bool expired() const {
return ref_count == nullptr || *ref_count == 0;
}
shared_ptr<T> lock() const {
if (expired()) {
return shared_ptr<T>();
}
return shared_ptr<T>(*this);
}
void reset() {
m_ptr = nullptr;
ref_count = nullptr;
}
void swap(weak_ptr& wp) {
std::swap(m_ptr, wp.m_ptr);
std::swap(ref_count, wp.ref_count);
}
size_t use_count() {
return ref_count != nullptr ? *ref_count : 0;
}
};
}