系列文章目录
文章目录
前言
暂不考虑支持多线程
常用STL的简单实现,主要内容百行左右完成,意在理解STL的原理
● 智能指针模板
SharedPtr
#include <assert.h>
#include <atomic>
template <class T>
class SharedPtr
{
public:
typedef T element_type;
explicit SharedPtr(T* ptr = nullptr) : m_ref(nullptr)
{
if (ptr) m_ref = new reftype(ptr);
}
template <class Deleter>
explicit SharedPtr(T* ptr, Deleter d) : m_ref(nullptr)
{
if (ptr) m_ref = new reftye_with_deleter<Deleter>(ptr, d);
}
SharedPtr(const SharedPtr& tocopy)
{
Acquire(tocopy.m_ref);
}
~SharedPtr()
{
Release();
}
SharedPtr& operator=(const SharedPtr& tocopy)
{
if (this != &tocopy)
{
Release();
Acquire(tocopy.m_ref);
}
return *this;
}
SharedPtr& operator=(T* ptr)
{
if (get() != ptr)
{
Release();
if (ptr) m_ref = new reftype(ptr);
}
return *this;
}
T* get() const
{
return m_ref ? m_ref->m_ptr : nullptr;
}
void reset(T* ptr = nullptr)
{
Release();
if (ptr) m_ref = new reftype(ptr);
}
template <class Deleter>
void reset(T* ptr, Deleter d)
{
Release();
if (ptr) m_ref = new reftye_with_deleter<Deleter>(ptr, d);
}
bool unique() const { return m_ref ? m_ref->m_count == 1 : true; }
long use_count() const { return m_ref ? m_ref->m_count.load() : 0; }
// test for pointer validity: defining conversion to unspecified_bool_type
// and not more obvious bool to avoid implicit conversions to integer types
typedef T*(SharedPtr<T>::*unspecified_bool_type)() const;
operator unspecified_bool_type() const
{
if (m_ref && m_ref->m_ptr) return &SharedPtr<T>::get;
else nullptr;
}
T& operator*() const
{
assert(m_ref && m_ref->m_ptr);
return *( m_ref->m_ptr);
}
T* operator->() const
{
assert(m_ref && m_ref->m_ptr);
return m_ref->m_ptr;
}
private:
struct reftype
{
reftype(T* ptr) : m_ptr(ptr), m_count(1) {}
virtual ~reftype() {}
virtual void delete_ptr() { delete m_ptr; }
T* m_ptr;
std::atomic_int m_count;
};
template <class Deleter>
struct reftye_with_deleter: public reftype
{
reftye_with_deleter(T* ptr, Deleter d) : reftype(ptr), m_deleter(d) {}
virtual void delete_ptr() override
{
m_deleter(this->m_ptr);
}
Deleter m_deleter;
};
reftype* m_ref;
void Acquire(reftype* ref)
{
m_ref = ref;
if (ref) ref->m_count.fetch_add(1);
}
void Release()
{
if (m_ref)
{
if (! --m_ref->m_count )
{
m_ref->delete_ptr();
delete m_ref;
}
m_ref = nullptr;
}
}
};
template <class T, class U>
bool operator==(const SharedPtr<T>& a, const SharedPtr<U>& b)
{
return a.get() == b.get();
}
template <class T, class U>
bool operator!=(const SharedPtr<T>& a, const SharedPtr<U>& b)
{
return a.get() != b.get();
}
//------------------------------------------------------------------------------
#include <iostream>
#include <stdio.h>
class TestSt
{
public:
char buf[1024];
char bux[4096];
public:
TestSt()
{
printf(" const %p\n", this);
};
~TestSt()
{
printf("~TestSt: %p\n", this);
}
};
int main()
{
std::atomic_int at;
SharedPtr<TestSt> p_st(new TestSt());
SharedPtr<TestSt> p_st2(p_st);
SharedPtr<TestSt> p_st3(new TestSt());
p_st3 = p_st2;
std::cout << p_st.use_count() << " " << p_st2.use_count() << " "
<< p_st3.use_count() << " " << std::endl;
}
● Vector
auto p = new T[N]; 申请空间,为每个元素p[i]调用T的构造函数
delete[] p; 先为每个元素调用析构函数,释放空间
1. 简单版本
new (m_values+i) T(val); 和 m_values[i] = val并不等价
当value_type包含虚函数时后者不能正确处理虚函数表指针,而前者却可以。这或许也是C和C++不兼容的证据?
如图所示,new (m_values+i) T(val)
可以正确处理虚表指针,而m_values[i] = val
的_vptr.TestSt = 0x0
#include <stdlib.h>
#include <algorithm>
template <class T>
class Vector
{
private:
T* m_values;
size_t m_size, m_capacity;
public:
typedef T value_type;
typedef T* iterator;
Vector(): m_values(nullptr), m_size(0), m_capacity(0) {}
~Vector()
{
for (size_t i = 0; i < m_size; i++)
{
m_values[i].~T();
}
free(m_values);
m_values = nullptr;
m_size = m_capacity = 0;
}
Vector(size_t n, const T& val): m_values(nullptr), m_size(n),m_capacity(n)
{
m_values = (T*)malloc(sizeof(T) * m_capacity);
for (size_t i = 0; i < n; i++)
{
new (m_values+i) T(val);
}
}
Vector(const Vector<T>& tocopy)
{
m_values = (T*)malloc(sizeof(T) * tocopy.m_capacity);
m_size = tocopy.m_size;
m_capacity = tocopy.m_capacity;
for (size_t i = 0; i < m_size; i++)
{
new (m_values+i) T(tocopy.m_values[i]);
}
}
Vector<T>& operator=(const Vector<T>& tocopy)
{
if (&tocopy == this) return *this;
Vector<T> tmp(tocopy);
std::swap(m_values, tmp.m_values);
std::swap(m_size, tmp.m_size);
std::swap(m_capacity, tmp.m_capacity);
return *this;
}
value_type& operator[](size_t idx)
{
return m_values[idx];
}
void push_back(const T& val)
{
if (m_size + 1 > m_capacity)
{
m_capacity = m_capacity ? 2*m_capacity : 1;
T* tmp = (T*)malloc(sizeof(T) * m_capacity);
for (size_t i = 0; i < m_size; i++)
{
new (tmp+i) T(m_values[i]);
m_values[i].~T();
}
free(m_values);
m_values = tmp;
}
new (m_values+m_size) T(val);
++m_size;
}
void pop_back()
{
--m_size;
m_values[m_size].~T();
}
void clear()
{
for (size_t i = 0; i < m_size; i++)
{
m_values[i].~T();
}
m_size = 0;
}
size_t size() { return m_size; }
iterator begin()
{
return m_values;
}
iterator end()
{
return m_values + m_size;
}
};