练习 16.28:编写你自己版本的shared_ptr和unique_ptr.
思路:由现在在书中学到的内容,实现一个智能指针使用引用计数的方式来实现。同时并没有实现weak_ptr,因此实现智能指针是比较简单的。我在实现过程中一部分参考了std的写法,比起我之前的写法简洁了不少,但有一些特性因为不清楚std怎么实现的,不过为了追求与std的一致性,还是实现了,这一部分代码会很不自然。同时在shared_ptr实现中使用了copy and swap技术,不仅代码变得简洁了许多,同时也顺带解决了一些问题。
my_shared_ptr.h:
#ifndef MY_SHARED_PTR_H
#define MY_SHARED_PTR_H
template<typename T> class my_shared_ptr;
template<typename T>
void swap(my_shared_ptr<T> &lhs, my_shared_ptr<T> &rhs) noexcept {
using std::swap;
swap(lhs.ptr, rhs.ptr);
swap(lhs.use, rhs.use);
swap(lhs.del, rhs.del);
}
template<typename T>
class my_shared_ptr {
friend void swap<T>(my_shared_ptr<T> &, my_shared_ptr<T> &) noexcept;
using Deleter = std::function<void(T *)>;
public:
my_shared_ptr() :
ptr(nullptr), use(new unsigned int(0)) { }
my_shared_ptr(T *);
my_shared_ptr(nullptr_t);
my_shared_ptr(const my_shared_ptr &rhs);
my_shared_ptr(my_shared_ptr &&rhs)noexcept;
my_shared_ptr(T *, const Deleter &deleter);
my_shared_ptr(nullptr_t, const Deleter &deleter) = delete;
my_shared_ptr(const my_shared_ptr &rhs, const Deleter &deleter);
my_shared_ptr(my_shared_ptr &&rhs, const Deleter &deleter)noexcept;
my_shared_ptr &operator=(my_shared_ptr)noexcept; //使用拷贝并交换技术
explicit operator bool() const {
return ptr != nullptr;
}
T &operator*() const {
return *ptr;
}
T *operator->() const {
return ptr;
}
T *get() const {
return ptr;
}
unsigned int use_count() const {
return *use;
}
bool unique() const {
return use_count() == static_cast<unsigned int>(1);
}
void reset();
void reset(T *);
void reset(nullptr_t) = delete;
void reset(T *, const Deleter &);
void reset(nullptr_t, const Deleter &) = delete;
void swap(my_shared_ptr &rhs) {
using std::swap;
swap(ptr, rhs.ptr);
swap(use, rhs.use);
swap(del, rhs.del);
}
~my_shared_ptr();
private:
void try_free();
T *ptr;
function<void(T *)> del;
unsigned int *use;
};
template<typename T>
my_shared_ptr<T>::my_shared_ptr(T *rhs) :
ptr(rhs), use(new unsigned int(1)), del(nullptr) { }
template<typename T>
my_shared_ptr<T>::my_shared_ptr(nullptr_t) :
ptr(nullptr), use(new unsigned int(0)), del(nullptr) { }
template<typename T>
my_shared_ptr<T>::my_shared_ptr(const my_shared_ptr &rhs) :
ptr(rhs.ptr), use(rhs.use), del(rhs.del) {
if (ptr)++ *use;
}
template<typename T>
my_shared_ptr<T>::my_shared_ptr(my_shared_ptr &&rhs) noexcept :
ptr(rhs.ptr), use(rhs.use), del(rhs.del) {
rhs.ptr = nullptr;
if (ptr)++ *use;
}
template<typename T>
my_shared_ptr<T>::my_shared_ptr(T *rhs, const Deleter &deleter) :
ptr(rhs), use(new unsigned int(1)), del(deleter) { }
template<typename T>
my_shared_ptr<T>::my_shared_ptr(const my_shared_ptr &rhs, const Deleter &deleter) :
ptr(rhs.ptr), use(rhs.use), del(deleter) {
if (ptr)++ *use;
}
template<typename T>
my_shared_ptr<T>::my_shared_ptr(my_shared_ptr &&rhs, const Deleter &deleter) noexcept :
ptr(rhs.ptr), use(rhs.use), del(deleter) {
rhs.ptr = nullptr;
if (ptr)++ *use;
}
template<typename T>
my_shared_ptr<T> &my_shared_ptr<T>::operator=(my_shared_ptr rhs) noexcept {
rhs.swap(*this);
return *this;
}
template<typename T>
void my_shared_ptr<T>::reset() {
my_shared_ptr().swap(*this);
}
template<typename T>
void my_shared_ptr<T>::reset(T *rhs) {
my_shared_ptr(rhs).swap(*this);
}
template<typename T>
void my_shared_ptr<T>::reset(T *rhs, const Deleter &deleter) {
my_shared_ptr(rhs, deleter).swap(*this);
}
template<typename T>
void my_shared_ptr<T>::try_free() {
if (*use == 0) return;
if (-- * use == 0) {
delete use;
use = nullptr;
del ? del(ptr) : delete ptr;
ptr = nullptr;
}
}
template<typename T>
my_shared_ptr<T>::~my_shared_ptr() {
try_free();
}
#endif
my_unique_ptr.h:
#ifndef MY_UNIQUE_PTR_H
#define MY_UNIQUE_PTR_H
template<typename T, typename D> class my_unique_ptr;
template<typename T, typename D>
void swap(my_unique_ptr<T, D> &lhs, my_unique_ptr<T, D> &rhs) {
using std::swap;
swap(lhs.ptr, rhs.ptr);
}
template<typename T, typename D = std::default_delete<T>>
class my_unique_ptr {
friend void swap<T, D>(my_unique_ptr &, my_unique_ptr &);
public:
my_unique_ptr() :
ptr(nullptr), del(D()) { }
my_unique_ptr(T *);
my_unique_ptr(T *, const D &);
my_unique_ptr(const D &);
my_unique_ptr(my_unique_ptr &&)noexcept;
my_unique_ptr &operator=(my_unique_ptr &&)noexcept;
my_unique_ptr &operator=(nullptr_t)noexcept;
T *release();
void reset();
void reset(T *);
explicit operator bool() const{
return ptr != nullptr;
}
T &operator*() const {
return *ptr;
}
T *operator->() const {
return ptr;
}
T *get() const {
return ptr;
}
void swap(my_unique_ptr &lhs) {
using std::swap;
swap(ptr, lhs.ptr);
}
~my_unique_ptr();
private:
T *ptr;
std::function<void(T *)> del;
};
template<typename T, typename D>
my_unique_ptr<T, D>::my_unique_ptr(T *rhs) :
ptr(rhs), del(D()) { }
template<typename T, typename D>
my_unique_ptr<T, D>::my_unique_ptr(T *rhs, const D &deleter) :
ptr(rhs), del(deleter) { }
template<typename T, typename D>
my_unique_ptr<T, D>::my_unique_ptr(const D &deleter) :
ptr(nullptr), del(deleter) { }
template<typename T, typename D>
my_unique_ptr<T, D>::my_unique_ptr(my_unique_ptr &&rhs) noexcept :
ptr(rhs.ptr), del(rhs.del) {
rhs.ptr = nullptr;
}
template<typename T, typename D>
my_unique_ptr<T, D> &my_unique_ptr<T, D>::operator=(my_unique_ptr &&rhs) noexcept {
if (this != &rhs) {
reset(rhs.ptr);
rhs.ptr = nullptr;
}
return *this;
}
template<typename T, typename D>
my_unique_ptr<T, D> &my_unique_ptr<T, D>::operator=(nullptr_t) noexcept {
reset();
return *this;
}
template<typename T, typename D>
T *my_unique_ptr<T, D>::release() {
T *ret = ptr;
ptr = nullptr;
return ret;
}
template<typename T, typename D>
void my_unique_ptr<T, D>::reset() {
if (ptr) del(ptr);
ptr = nullptr;
}
template<typename T, typename D>
void my_unique_ptr<T, D>::reset(T *rhs) {
if (ptr) del(ptr);
ptr = rhs;
}
template<typename T, typename D>
my_unique_ptr<T, D>::~my_unique_ptr() {
if (ptr) del(ptr);
ptr = nullptr;
}
#endif