✍个人博客:Pandaconda-CSDN博客
📣专栏地址:http://t.csdnimg.cn/fYaBd
📚专栏简介:在这个专栏中,我将会分享 C++ 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
1. C++11 有哪些新特性?
- 智能指针
- nullptr 替代 NULL
- 引入了 auto 和 decltype 这两个关键字实现了类型推导
- 基于范围的 for 循环 for(auto& i : res){}
- 类和结构体的中初始化列表
- Lambda 表达式(匿名函数)
- std::forward_list(单向链表)
- 右值引用和 move 语义
- foreach:可以遍历数组、容器等。底层通过指针或迭代器实现的
- …
2. 智能指针的原理、常用的智能指针及实现
原理
智能指针是一个类,用来存储指向动态分配对象的指针,负责自动释放动态分配的对象,防止堆内存泄漏。动态分配的资源,交给一个类对象去管理,当类对象声明周期结束时,自动调用析构函数释放资源。
常用的智能指针
(1) shared_ptr
实现原理:采用引用计数器的方法,允许多个智能指针指向同一个对象,每当多一个指针指向该对象时,指向该对象的所有智能指针内部的引用计数加 1,每当减少一个智能指针指向对象时,引用计数会减 1,当计数为 0 的时候会自动的释放动态分配的资源。
- 智能指针将一个计数器与类指向的对象相关联,引用计数器跟踪共有多少个类对象共享同一指针
- 每次创建类的新对象时,初始化指针并将引用计数置为 1。
- 当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数。
- 对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至 0,则删除对象),并增加右操作数所指对象的引用计数。
- 调用析构函数时,构造函数减少引用计数(如果引用计数减至 0,则删除基础对象)。
(2) unique_ptr
scoped_ptr 和 unique_ptr 都是将默认的拷贝和复制函数给 delete 了,但是 unique_ptr 多了右值传递的函数。
unique_ptr 采用的是独享所有权语义,一个非空的 unique_ptr 总是拥有它所指向的资源。转移一个 unique_ptr 将会把所有权全部从源指针转移给目标指针,源指针被置空;
所以 unique_ptr 不支持普通的拷贝和赋值操作,不能用在 STL 标准容器中;局部变量的返回值除外(因为编译器知道要返回的对象将要被销毁);
如果你拷贝一个 unique_ptr,那么拷贝结束后,这两个 unique_ptr 都会指向相同的资源,造成在结束时对同一内存指针多次释放而导致程序崩溃。
// 通过构造函数初始化对象
std::unique_ptr<int> ptr1(new int(10));
// error, 不允许将一个unique_ptr赋值给另一个unique_ptr
std::unique_ptr<int> ptr2 = ptr1;
使用 reset 方法可以让 unique_ptr 解除对原始内存的管理,也可以用来初始化一个独占的智能指针:
int main()
{
unique_ptr<int> ptr1(new int(10));
unique_ptr<int> ptr2 = move(ptr1);
ptr1.reset();
ptr2.reset(new int(250));
return 0;
}
(3) weak_ptr
weak_ptr:弱引用。 引用计数有一个问题就是互相引用形成环(环形引用),这样两个指针指向的内存都无法释放。需要使用 weak_ptr 打破环形引用。weak_ptr 是一个弱引用,它是为了配合 shared_ptr 而引入的一种智能指针,它指向一个由 shared_ptr 管理的对象而不影响所指对象的生命周期,也就是说,它只引用,不计数。如果一块内存被 shared_ptr 和 weak_ptr 同时引用,当所有 shared_ptr 析构了之后,不管还有没有 weak_ptr 引用该内存,内存也会被释放。所以 weak_ptr 不保证它指向的内存一定是有效的,在使用之前使用函数 lock() 检查 weak_ptr 是否为空指针。
注意:weak_ptr 不能调用 * 和 -> 符号。
(4) auto_ptr
主要是为了解决 “有异常抛出时发生内存泄漏” 的问题 。因为发生异常而无法正常释放内存。
auto_ptr 有拷贝语义,拷贝后源对象变得无效,这可能引发很严重的问题;而 unique_ptr 则无拷贝语义,但提供了移动语义,这样的错误不再可能发生,因为很明显必须使用 std::move() 进行转移。
auto_ptr 不支持拷贝和赋值操作,不能用在 STL 标准容器中。STL 容器中的元素经常要支持拷贝、赋值操作,在这过程中 auto_ptr 会传递所有权,所以不能在 STL 中使用。
3. 智能指针 shared_ptr 代码实现
template<typename T>
class SharedPtr
{
public:
SharedPtr(T* ptr = NULL):_ptr(ptr), _pcount(new int(1))
{}
SharedPtr(const SharedPtr& s):_ptr(s._ptr), _pcount(s._pcount){
(*_pcount)++;
}
SharedPtr<T>& operator=(const SharedPtr& s){
if (this != &s)
{
if (--(*(this->_pcount)) == 0)
{
delete this->_ptr;
delete this->_pcount;
}
_ptr = s._ptr;
_pcount = s._pcount;
*(_pcount)++;
}
return *this;
}
T& operator*()
{
return *(this->_ptr);
}
T* operator->()
{
return this->_ptr;
}
~SharedPtr()
{
--(*(this->_pcount));
if (*(this->_pcount) == 0)
{
delete _ptr;
_ptr = NULL;
delete _pcount;
_pcount = NULL;
}
}
private:
T* _ptr;
int* _pcount;//指向引用计数的指针
};