C++高频面试考点 -- 智能指针

发布于:2025-05-24 ⋅ 阅读:(19) ⋅ 点赞:(0)

C++高频面试考点 – 智能指针

C++11中引入智能指针的概念,方便堆内存管理。这是因为使用普通指针,容易造成堆内存泄漏,二次释放,程序发生异常时内存泄漏等问题。

智能指针在C++11版本之后提供,包含在头文件<memory>中,shared_ptrunique_ptrweak_ptrauto_ptr

  1. shared_ptr

    shared_ptr使用引用计数、每一个shared_ptr的拷贝都指向相同的内存。每使用它一次,内部的引用计数就加一,每析构一次,内部的引用计数就减一,减为0的时候,自动删除所指向的堆内存。shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁。

    智能指针是一个模板类,可以指定类型,传入指针通过构造函数初始化。也可以使用make_shared函数初始化。不能将指针直接赋值给一个智能指针,一个是类,一个是指针。

    例如:std::shared_ptr <int> p = new int(1);的写法是错误的。

  2. unique_ptr

    unique_ptr“唯一”拥有其所指对象,也就是独享所有权语义,同一时刻只能有一个unique_ptr指向给定对象(禁止通过拷贝语义、只有移动语义来实现)。相比于原始指针,unique_ptr用于其RAII的特性,使得在出现异常的情况下,动态资源能够得到释放。

    unique_ptr指针本身的生命周期:从unique_ptr指针创建时开始,直到离开作用域,离开作用域时,若其指向对象,则将其所指对象销毁。

    unique_ptr指针与其所知对象的关系:在智能指针生命周期内,可以改变智能指针所指对象,如创建智能指针时通过构造函数指定、通过reset方法重新指定、通过release方法释放所有权、通过移动语义转移所有权。

  3. weak_ptr

    weak_ptr是一种不控制对象生命周期的智能指针,它指向一个shared_ptr管理的对象,进行该对象的内存管理的是哪个强引用的shared_ptrweak_ptr设计的目的是为了配合shared_ptr而引入的一种智能指针来协助shared_ptr。这是因为引用计数有一个问题就是互相引用形成环,这样两个指针指向的内存都无法释放。需要weak_ptr来打破环形引用。如果一块内存被shared_ptrweak_ptr同时引用,当所有shared_ptr析构了之后,不管还有没有weak_ptr引用该内存,内存也会被释放。所以weak_ptr不保证它指向的内存一定时有效的,在使用之前使用函数lock()检查weak_ptr是否为空指针。

  4. auto_ptr

    auto_ptr主要是为了解决“有异常抛出时发生内存泄漏”的问题。因为发生异常而无法正常释放内存。

    auto_ptr不支持拷贝和赋值的操作,不能用在STL标准容器中。STL容器中的元素经常要支持拷贝、赋值的操作,在这过程中auto_ptr会传递所有权,所以不能在STL中使用

手撕shared_ptr

#pragma once
namespace my_shared_ptr 
{   
    template <typename T>
    class shared_ptr
    {
    private:
        /* data */
        T *m_data;
        int *m_count; //计数
    
    public:
        shared_ptr() : m_data(nullptr), m_count(nullptr) {}
        shared_ptr(T *data) : m_data(data) 
        {
            if(data != nullptr) 
            {
                m_count = new int(1);
            }
        }
        shared_ptr(const shared_ptr<T> & other) : m_data(other.m_data), m_count(other.m_count)
        {
            // 拷贝构造函数
            if(m_data != nullptr)
            {
                (*m_count) ++;
            }
        }
        shared_ptr(shared_ptr<T> && other) noexcept : m_data(other.m_data), m_count(other.m_count)
        {
            // 移动构造函数
            other.m_data = nullptr;
            other.m_count = nullptr;

        }
        ~shared_ptr()
        {
            if(m_data != nullptr) 
            {
                (*m_count) --;
                if(*m_count <= 0)
                {
                    delete m_data;
                    m_data = nullptr;
                    delete m_count;
                    m_count = nullptr;
                }
            }
        }

        T * get() const
        {
            return m_data;
        }

        void reset(T *data = nullptr)
        {
            if(m_data == data)
            {
                return;
            }
            if(m_data == nullptr) 
            {
                if(data != nullptr)
                {
                    m_data = data;
                    m_count = new int(1);
                }
                return;
            }
            (*m_count) --;
            if(*m_count <= 0) 
            {
                delete m_data;
                m_data = nullptr;
                delete m_count;
                m_count = nullptr;
            }
            m_data = data;
            if(data != nullptr) 
            {
                m_count = new int(1);
            }
        }

        int use_count() const
        {
            if(m_data == nullptr)
            {
                return 0;
            }
            return *m_count;
        }

        bool unique() const
        {
            // 判断是否只有一个智能指针指向该对象
            if(m_data == nullptr)
            {
                return false;
            }
            return *m_count == 1;
        }

        void swap(shared_ptr<T> & other)
        {
            auto data = other.data;
            auto count = other.m_count;
            other.m_data = m_data;
            other.m_count = m_count;
            m_data = data;
            m_count = count;
        }

        T* operator -> () const
        {
            return m_data;
        }

        T& operator * () const
        {
            return *m_data;
        }

        explicit operator bool() const noexcept
        {
            return m_data != nullptr;
        }

        shared_ptr & operator = (const shared_ptr<T> & other)
        {
            if(this == &other)
            {
                return *this;
            }
            m_data = other.m_data;
            m_count = other.m_count;
            (*m_count)++;
            return *this;
        }

        shared_ptr & operator = (shared_ptr<T> && other) noexcept
        {
            if(this == &other) 
            {
                return *this;
            }
            m_data = other.m_data;
            m_count = other.m_count;
            other.m_data = nullptr;
            other.m_count = nullptr;
            return *this;
        }
    };
    
}

测试代码

#include <string>
#include <iostream>
#include "shared_ptr.h"
using namespace my_shared_ptr;

class Test
{
private:
    std::string m_name;
public:
    Test(/* args */) = default;
    void name(const std::string & name);
    std::string get_name() const;
    ~Test();
};

Test::~Test()
{
    std::cout << "Test is deleted" << std::endl;
}

void Test::name(const std::string & name) 
{
    m_name = name;
}

std::string Test::get_name() const
{
    return m_name;
}

int main() 
{
    auto p = new Test();
    shared_ptr <Test> sp(p);

    sp -> name("jack");
    std::cout << sp->get_name() << std::endl;
    std::cout << sp.use_count() << std::endl;

    shared_ptr <Test> sp2;
    sp2 = sp;
    std::cout << sp2.use_count() << std::endl;
    return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到