• C++中的智能指针


    在这里插入图片描述
    智能指针是在 C + + 14 C++14 C++14中新引入的,所以在编译的时候最好加入 " − s t d = c + + 14 " "-std=c++14" "std=c++14"的编译选项。智能指针一共有两种,分别是 u n i q u e _ p t r unique\_ptr unique_ptr s h a r e d _ p t r shared\_ptr shared_ptr

    u n i q u e _ p t r unique\_ptr unique_ptr

    u n i q u e _ p t r unique\_ptr unique_ptr可以使用 m a k e _ u n i q u e make\_unique make_unique来生成:

      template<typename _Tp, typename... _Args>
        inline typename _MakeUniq<_Tp>::__single_object
        make_unique(_Args&&... __args)
        { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
    
    • 1
    • 2
    • 3
    • 4

    可以看出 m a k e _ u n i q u e make\_unique make_unique是一个模板函数,将返回一个 _ T p \_Tp _Tp类型的指针,也就是假设有一个 p o i n t point point类:

    struct point
    {
    	int x, y;
    	point(int x, int y)
    	{
    		this->x = x;
    		this->y = y;
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    然后声明一个指针:

    std::unique_ptr<point> x = make_unique<point>(3, 5);
    
    • 1

    x x x为一个指向 p o i n t ( 3 , 5 ) point(3,5) point(3,5)的指针,然而由于其" u n q i u e unqiue unqiue"的特性, x x x不可被拷贝构造以及拷贝赋值,在源码里,其拷贝构造以及拷贝赋值被定义成以下的形式:

    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;
    
    • 1
    • 2

    C + + C++ C++中,“ = d e l e t e = delete =delete"是一种特殊的函数声明方式,用于禁用或删除某个函数的默认实现。当一个函数被声明为” = d e l e t e = delete =delete"时,编译器将不会生成该函数的默认实现,并且在尝试调用该函数时会引发编译错误。
    然而,有的时候需要将 x x x指向的内存转给其他指针,那么这个时候,只有唯一的一种方法,就是:

    auto y = std::move(x);
    //or std::unique_ptr y = std::move(x);
    
    • 1
    • 2

    s h a r e d _ p t r shared\_ptr shared_ptr

    s h a r e d _ p t r shared\_ptr shared_ptr不同于 u n i q u e _ p t r unique\_ptr unique_ptr,其可以通过拷贝赋值给其他指针,以下分别是其拷贝构造以及拷贝赋值函数。

    shared_ptr& operator=(const shared_ptr& _Right) noexcept
    		{	// assign shared ownership of resource owned by _Right
    		shared_ptr(_Right).swap(*this);
    		return (*this);
    		}
    shared_ptr(const shared_ptr& _Other) noexcept
    		{	// construct shared_ptr object that owns same resource as _Other
    		this->_Copy_construct_from(_Other);
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    也就是说, s h a r e d _ p t r shared\_ptr shared_ptr可以通过以下方式构造:

    std::shared_ptr<point> x = make_shared<point>(3, 5);
    auto y = x;
    auto z(x);
    
    • 1
    • 2
    • 3

    同时可以通过 u s e _ c o u n t use\_count use_count方法统计一块相同的内存被几个指针共享:

    cout << x.use_count() << endl;
    
    • 1

    共享指针有以下几个 t r i c k trick trick

    1. 当共享指针被拷贝构造或者拷贝赋值的时候,指向的内存才算被共享了一次,所以上面的那段代码输出的结果为 3 3 3,然而如果是进行浅拷贝的话,不算做一次共享:
    auto y = std::move(x);
    cout<<y.use_count()<<x.use_count()<<endl;
    //该结果为3 0
    
    • 1
    • 2
    • 3
    1. 如果是传入函数并且打印 u s e _ c o u n t use\_count use_count,也有以下两种情况。
    void func(std::shared_ptr<point> x)
    {
    	cout << x.use_count() << endl;
    }
    int main(void)
    {
    	std::shared_ptr<point> x = make_shared<point>(3, 5);
    	auto y = x;
    	auto z(x);
    	cout << x.use_count() << endl;
    	func(std::move(x));//这个右值引用如果给一个左值里面就空了
    	cout << x.use_count() << endl;
    }
    //本结果为
    //3 3 0
    //如果调用x的其他属性会报段错误。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    void func(std::shared_ptr<point>&& x)
    {
    	cout << x.use_count() << endl;
    }
    int main(void)
    {
    	std::shared_ptr<point> x = make_shared<point>(3, 5);
    	auto y = x;
    	auto z(x);
    	cout << x.use_count() << endl;
    	func(std::move(x));//这个右值引用如果给一个左值里面就空了
    	cout << x.use_count() << endl;
    }
    //这个结果为3 3 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    如果不按右值引用传入:

    void func(std::shared_ptr<point> x)
    {
    	cout << x.use_count() << endl;
    }
    int main(void)
    {
    	std::shared_ptr<point> x = make_shared<point>(3, 5);
    	auto y = x;
    	auto z(x);
    	cout << x.use_count() << endl;
    	func(x);//这个右值引用如果给一个左值里面就空了
    	cout << x.use_count() << endl;
    }
    //这个结果是3 4 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    Mysql数据库日志的用法解读
    Redis中有大量未设置过期时间的缓存应该如何处理?
    IDEA提交本地项目到Gitee远程仓库
    Java寻找两个正序数组的中位数
    持续部署:提高敏捷加速软件交付(内含教程)
    vulfocus——struts2-cve_2017_9791
    Vue中组件间的传值(子传父,父传子)
    前端经典面试题 | Vue组件间的通信方式
    2022年10月30:rabbitmq学习、springboot整合rabbitmq
    CentOS安装配置freeIPA
  • 原文地址:https://blog.csdn.net/weixin_52205764/article/details/133907444