【C++ 面试 - 新特性】每日 3 题(一)

✍个人博客: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;//指向引用计数的指针
};
  • 17
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值