1. 内存管理
C++的内存管理大致可分为以下几种:
(1)堆的内存管理 – 使用new
、delete
进行,由内存管理器完成内存分配、内存对齐、内存合并等操作。
(2)栈的内存管理 – 通过栈指针在栈帧上的移动进行分配,栈顶是逐渐靠近低地址位的,不会出现内存碎片,通过栈展开防止异常不能析构的情况。
说到内存管理不能少说的东西:
(1)数组
(2)GC,垃圾回收
(3)各种池技术,如对象池、内存池等
(4)new和delete
(5)智能指针
2. new
2.1 new的本质
当我们new
一个对象时,编译器会做如下事情:
/** new T(…) */
{
// void *operator new(size_t) throw(bad_alloc);
// 分配对应的sizeof(T)内存,如果失败,则会抛出bad_alloc异常
void* temp = operator new(sizeof(circle));
try
{
// 强制转化为T类型
T* ptr = static_cast<T*>(temp);
// 调用T类型的构造函数
ptr->T(…);
return ptr;
}
catch (...)
{
// 如果有异常,则delete
operator delete(ptr);
throw;
}
}
/* delete T **/
if (ptr != nullptr)
{
ptr->~T();
operator delete(ptr);
}
2.2 应用场景
使用new进行返回值时,需要对其构造和析构函数进行封装
template <typename T>
class T_Wrapper
{
public:
/** 封装的接收返回值是T指针的构造函数 */
explicit T_wrapper(T* ptr = nullptr) : ptr_(ptr)
{
}
/** 析构函数 */
~shape_wrapper()
{
delete ptr_;
}
T* get() const
{
return ptr_;
}
private:
T* ptr_;
};
T* Create_T()
{
return new T;
}
void f()
{
T_Wrapper ptr_wrapper(Create_T());
}
可以发现此处的T_Wrapper很类似于智能指针,承担了管理任意T对象的指针,防止其内存泄漏的作用。即使用基于栈和析构函数的RAII来管理堆内存。
3. 智能指针的本质
直接手动实现一个基础的智能指针,其本质就能很清晰的呈现在面前,在下述代码中会有适当的注释:
/**
* 计数类
* 用于存储引用计数
*/
class shared_count {
public:
// 构造时自动赋值为1
shared_count() noexcept : count_(1)
{
}
// 计数增加
void add_count() noexcept
{
++count_;
}
// 计数减少,为了和0比较,因此返回
long reduce_count() noexcept
{
return --count_;
}
long get_count() const noexcept
{
return count_;
}
private:
long count_;
};
/**
* 实现智能指针,模拟其所有功能
*/
template <typename T>
class smart_ptr
{
public:
// 声明友元类,用于访问私有变量
template <typename U>
friend class smart_ptr;
//
explicit smart_ptr(T* ptr = nullptr) : ptr_(ptr)
{
if (ptr)
{
shared_count_ = new shared_count();
}
}
// 析构函数,如果计数为0并且ptr_存在时,进行析构
~smart_ptr()
{
if (ptr_ && ! shared_count_->reduce_count())
{
delete ptr_;
delete shared_count_;
}
}
// 拷贝构造函数,引用计数加1
smart_ptr(const smart_ptr& other)
{
ptr_ = other.ptr_;
if (ptr_)
{
other.shared_count_->add_count();
shared_count_ = other.shared_count_;
}
}
// 拷贝构造函数,使用模板,用于父子类的拷贝构造
template <typename U>
smart_ptr(const smart_ptr<U>& other) noexcept
{
ptr_ = other.ptr_;
if (ptr_)
{
other.shared_count_->add_count();
shared_count_ = other.shared_count_;
}
}
// 移动构造函数,将other的指针置空,同时引用计数不变
template <typename U>
smart_ptr(smart_ptr<U>&& other) noexcept
{
ptr_ = other.ptr_;
if (ptr_)
{
shared_count_ = other.shared_count_;
other.ptr_ = nullptr;
}
}
// 用于实现强制类型转换,由U类型转换到T
template <typename U>
smart_ptr(const smart_ptr<U>& other, T* ptr) noexcept
{
ptr_ = ptr;
if (ptr_)
{
other.shared_count_->add_count();
shared_count_ = other.shared_count_;
}
}
// 赋值运算符,注意:rhs是一个拷贝,和原来的空间无关
// 而这里拷贝一次,一定会调用拷贝构造函数,计算一定会加1
smart_ptr& operator=(smart_ptr rhs) noexcept
{
rhs.swap(*this);
return *this;
}
// 获得智能指针所管理的指针
T* get() const noexcept
{
return ptr_;
}
// 返回指针计数
long use_count() const noexcept
{
if (ptr_)
{
return shared_count_->get_count();
}
else
{
return 0;
}
}
// 调用std::swap,进行指针指针的交换
void swap(smart_ptr& rhs) noexcept
{
using std::swap;
swap(ptr_, rhs.ptr_);
swap(shared_count_, rhs.shared_count_);
}
// 重载*运算符
T& operator*() const noexcept
{
return *ptr_;
}
// 重载->运算符
T* operator->() const noexcept
{
return ptr_;
}
operator bool() const noexcept
{
return ptr_;
}
private:
// 所管理的原有指针
T* ptr_;
// 引用计数
shared_count* shared_count_;
};