关于C++
一、智能指针
1、C++中智能指针的作用
1)避免内存泄漏
2)语义转换(C++和Java 的语义区别)
2、 智能指针分类
1)auto_ptr
2)unique_ptr
3)shared_ptr
4)weak_ptr
3、智能指针的优缺点比较
1)auto_ptr(独占式)
该智能指针已经被用于赋值,赋值后便被剥夺了所有权,当再次访问的时候便会报错,即存在潜在的内存崩溃问题,(目前已被 unique_ptr 智能指针所代替)
2)unique_ptr(独占式)
禁用了拷贝构造函数和赋值运算符重载函数,从而避免了内存崩溃问题。同时重载了移动构造函数和移动赋值运算符,支持采用移动语义进行资源转移
3)shared_ptr(共享式)
所谓共享式智能指针,即同一时刻允许多个智能指针指向给定对象,并且采用引用计数的方法记录指向该对象的智能指针数量,当指针数量等于0时,自动释放内存。
- shared_ptr初始化
对于共享式智能指针的初始化方式有两种。
//采用new关键字
shared_ptr<int> p(new int(5));
//采用make_shared
shared_ptr<int> p = make_shared<int>(5);
对于使用make_shared的优点:
智能指针包含两个私有成员指针,引用计数和指向资源的指针。
1)如果我们使用new 去初始化shared_ptr 对象,首先 new 的过程会进行一次堆内存分配,当构造shared_ptr 对象的时候仍然需要进行一次堆内存的申请,供引用计数使用。而make_share则只需要分配一次内存
2)shared_ptr构造时,包含两步操作,(1)new一个堆内存,(2)分配一个引用计数区域管理该内存空间,并没有保证这两个步骤的原子性,当做了第(1)步,没有做第二步如果程序抛出了异常,将导致内存泄露,因此更推荐使用make_shared来分配内存。
对于使用make_shared的缺点:
1)智能指针中存在强引用计数和弱引用计数。 当强引用计数为0时,会释放引用的对象内存(执行析构函数),当弱引用计数为0时释放引用计数所占用的内存。因此当使用make_shared<>() 创建智能指针时,会只申请一块内存。由于弱引用计数的存在,make_shared申请的内存可能无法及时释放。 因为资源 和 引用计数共用同一块内存,只有当 强引用计数和弱引用计数都为0时才能释放make_shared 申请的一整块内存
- shared_ptr的手撕
template<typename T>
class smart_ptr {
public:
smart_ptr():count(0),data(nullptr) {}
smart_ptr(T *t):count(new int(1)),data(t) {}
//拷贝函数构造
smart_ptr(const smart_ptr<T> &ptr):count( &(++*ptr.count)),data(ptr.data ) {}
//重载解引用符号
T& operator*()
{
return *data;
}
//赋值运算符重载
smart_ptr<T>& operator=(const smart_ptr<T> &ptr) {
if (this->data == ptr.data) {
return *this;
}
//右值的引用计数加1
++*ptr.count;
//判断左侧的值的引用计数是非为0
if (--(*this->count) == 0) {
delete this->count;
delete this->data;
cout << "delete from ~" << endl;
}
//为左侧的智能指针重新赋值
count = ptr.count;
data = ptr.data;
return *this;
}
//返回引用计数
int refcount()
{
return *count;
}
~smart_ptr()
{
if (--*(this->count) == 0) {
delete data;
delete count;
cout << "delete from ~" << endl;
}
}
private:
int *count;
T * data;
};
4、面试相关问题
1)unique_ptr 不可以进行值传递传参,是否可以作为返回值?
可以。临时值可以执行移动构造函数。
2)智能指针的本质?
实际就是利用类的析构特性,离开作用域便会被析构掉。
3)智能指针是否线程安全?
share_ptr 不是线程安全的。shared_ptr的引用计数是原子的,因此在多线程环境下的构造、复制、析构都是线程安全的。同时指针也是线程安全的。但是 复制引用计数和复制指针这两步是分开的,有可能会被中断,因此对shared_ptr的操作不是原子的,也就是shared_ptr本身并不是线程安全的。
4)什么是Rall机制?
利用c++构造对象最终会被销毁的原则。用类封装资源,在构造函数中进行资源分配和初始化,在对象的生命周期内控制对资源的访问,最后在析构函数中完成对资源的释放