C++ 学习系列 -- 智能指针 make_shared 与 make_unique

这篇具有很好参考价值的文章主要介绍了C++ 学习系列 -- 智能指针 make_shared 与 make_unique。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一   make_shared 

1.1  make_shared 是什么?

      c++ 11 中 引入了智能指针 shared_ptr,以及一个模板函数 make_shared 来生成一个制定类型的 shared_ptr。

1.2  引入 make_shared ,解决了什么问题?

   make_shared的引入,主要有两点的提升:性能 与 异常安全

C++11 make_shared - 简书 (jianshu.com)

  •   性能

        有如下两种方式生成  shared_ptr

int  main()
{
    // 1.
    shared_ptr<string> p1(new string("66888"));
    cout << *p1 << endl;

    // 2.
    shared_ptr<string> p2 = make_shared<string>("888888");
    cout << *p2 << endl;
    
    return 0;
}

              使用 make_shared 性能要更好一些

  shared_ptr<string> p1(new string("66888"));  会分配两次内存

每个std::shared_ptr都指向一个控制块,控制块包含被指向对象的引用计数以及其他东西。这个控制块的内存是在std::shared_ptr的构造函数中分配的。因此直接使用new,需要一块内存分配给string,还要一块内存分配给控制块。

  使用   shared_ptr<string> p2 = make_shared<string>("888888");  分配一次内存

  一次分配就足够了。这是因为std::make_shared申请一个单独的内存块来同时存放 string 对象和控制块。

  •   异常安全
// d.h
#include<iostream>

class D
{
public:
    D()
    {
        std::cout << "constructor D " << std::endl;
    }
    ~D()
    {
        std::cout << "destructor D " << std::endl;
    }

};


// main.cpp

int getVal()
{
    throw 888;
    return 66;
}

void  init(shared_ptr<D> ptr, int val)
{

}

int main()
{
   // 1. 
   init(std::shared_ptr<D>(new D), getVal());
   
   // 2.
   init(std::make_shared<D>(), getVal());
   
   return 0;
}

  第 1 种的调用方式分为三步:

  1.  new D

  2. 调用 shared_ptr 类的构造函数

  3. 调用 getVal 函数  

        针对不同的编译器,上述三步的执行顺序可能不同,若是 其中的第 2 步 与第 3 步发生了调换,那么在执行 getVal 抛出异常后,就不会再执行 第 2 步,没有调用 shared_ptr 的构造函数,那么就无法用 shared_ptr 来管理 第 1 步分配出的内存。

  第 2 种方式,用 make_shared 就不会出现该问题,其分为两步

   1. make_shared 生成 shared_ptr 指针

   2.调用  getVal 函数  

上面的 1 步 与 2 步,即便发生顺序调换,也不会出现内存无法管理的情况

1.3   make_shared 源码解析

  template<typename _Tp, typename... _Args>
    inline shared_ptr<_Tp>
    make_shared(_Args&&... __args)
    {
      typedef typename std::remove_const<_Tp>::type _Tp_nc; // 去除 _Tp 的 const 特性,获取到其类本身
      return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(),
				       std::forward<_Args>(__args)...);
     // std::allocator会给我们分配一块_Tp_nc实例需要的内存空间
     // 完美转发(perfect forward)剩余构造函数的参数
    }
 

  template<typename _Tp, typename _Alloc, typename... _Args>
    inline shared_ptr<_Tp>
    allocate_shared(const _Alloc& __a, _Args&&... __args)
    {
      return shared_ptr<_Tp>(_Sp_make_shared_tag(), __a,
			     std::forward<_Args>(__args)...); // 调用 shared_ptr 的 private 构造函数
    }
 
​

make_shared 的参数是万能引用 && ,因此参数既可以接受左值也可以接受右值。

allocate_shared 是 shared_ptr 类的 friend 函数,因此可以调用 shared_ptr 的 private 构造函数。

总之,下面的 private 构造函数将实例内存与计数器模块的内存绑定在了一起。

template<typename _Alloc, typename... _Args>
         __shared_ptr(_Sp_alloc_shared_tag<_Alloc> __tag, _Args&&... __args)

详细解析见:从零开始写一个shared_ptr-make_shared源代码解析 - 知乎 (zhihu.com)

1.4  make_shared 使用例子

// person.h
class Person
{
public:
    Person(std::string name);
    Person(const Person& p);
    ~Person();

    std::string& getName();

    void setName(std::string& name);

private:
    std::string m_name;
};


// person.cpp
#include "person.h"
#include<iostream>
Person::Person(std::string name):m_name(name)
{
    std::cout << "Person constructor name: " << m_name << std::endl;
}

Person::Person(const Person& p)
{
    this->m_name = p.m_name;
    std::cout << "Person  copy constructor name: " << this->m_name << std::endl;
}

Person::~Person()
{
    std::cout << "Person destructor name: " << m_name << std::endl;
}

std::string& Person::getName()
{
    return m_name;
}

void Person::setName(std::string& name)
{
    this->m_name = name;
}



// main.cpp
void testSharedPtr2()
{
    // 1.
    shared_ptr<Person>  ptr(new Person("Tom"));
    cout << ptr->getName() << endl;


    // 2.
    shared_ptr<Person>  ptr2 = make_shared<Person>("Jerry");
    cout << ptr2->getName() << endl;

}

int main()
{
  
  testSharedPtr2();
  return 0;
}

二   make_unique 

2.1  make_unique 是什么?

        make_unique 是 c++14 加入标准库的,用于生成独占型指针 std::unique_ptr 

2.2  make_unique  解决了什么问题?

     用 make_unique 生成独占型指针代码量更少,符合现代 c++ 尽量避免使用 new  来构造的原则

2.3  make_unique  简单版实现

template<typename T, typename... Arg>  // 可能有多个参数,所以用 ...
unique_ptr<T>
my_make_unique(Arg&& ... s)  // 支持左值与右值,所以要用万能引用
{
    return unique_ptr<T>(new T(std::forward<Arg>(s)...));
}

int main()
{

   unique_ptr<string> ptr = my_make_unique<string>("abcdd");
   cout << *ptr << endl;

  return 0;
}

源码:std::make_unique, std::make_unique_for_overwrite - cppreference.com

2.4  make_unique  使用例子

很简单

int  main()
{

  std::unique_ptr<std::string> a = std::make_unique("6666");

  return 0;
}

参考:C++11 make_shared - 简书 (jianshu.com)

从零开始写一个shared_ptr-make_shared源代码解析 - 知乎 (zhihu.com)

​《Effective Modern C++》学习笔记之条款二十一:优先选用std::make_unique和std::make_shared,而非直接new - 知乎 (zhihu.com)文章来源地址https://www.toymoban.com/news/detail-691021.html

到了这里,关于C++ 学习系列 -- 智能指针 make_shared 与 make_unique的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++入门到精通】智能指针 shared_ptr 简介及C++模拟实现 [ C++入门 ]

    在 C++ 动态内存管理中,除了 auto_ptr 和 unique_ptr 之外,还有一种 智能指针 shared_ptr ,它可以让多个指针共享同一个动态资源,并且能够自动释放资源。 shared_ptr 通过引用计数的方式来管理内存,能够避免程序中出现悬空指针和内存泄漏等问题 。本文将介绍 shared_ptr 的简介和

    2024年01月22日
    浏览(36)
  • C++之weak_ptr与shared_ptr智能指针实例(一百九十五)

    简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏: Audio工程师进阶系列 【 原创干货持续更新中…… 】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:An

    2024年02月09日
    浏览(47)
  • C++中智能指针(unique_ptr、shared_ptr、weak_ptr)详解

    C++中的智能指针是一种 RAII(资源获取即初始化)机制的实现, 它可以在对象不再需要时自动释放相关资源。 智能指针通过封装指针对象并提供一些额外的功能,如 引用计数、自动内存管理、避免内存泄漏等, 使得指针使用更加安全和方便。 在C++中,有三种主要类型的智能

    2023年04月11日
    浏览(29)
  • 智能指针shared_ptr

    shared_ptr共享它指向的对象,内部采用计数机制来实现。当新的shared_ptr与对象关联时,引用计数加1;当shared_ptr超出作用域时,引用计数减1;当引用计数为0时,释放该对象; shared_ptrA p0 = std::make_sharedA(\\\"西红柿\\\");//C++11提供 重载了*和-操作符,可以像使用指针一样使用shared_ptr

    2023年04月23日
    浏览(29)
  • 【C++学习】智能指针

    🐱作者:一只大喵咪1201 🐱专栏:《C++学习》 🔥格言: 你只管努力,剩下的交给时间! 如上图代码所示,在Func中开辟动态空间,在调用完Division函数后释放该空间。 如果Division没有抛异常,那么动态空间会被正常释放。 如果Division抛了异常,就会去匹配对应的catch,而Fu

    2024年02月06日
    浏览(41)
  • C++智能指针学习——小谈引用计数

    目录 前言 控制块简介 共享控制块 引用计数与弱引用计数创建过程 __shared_ptr __shared_count _Sp_counted_base 弱引用计数增加过程 再谈共享控制块 __weak_count 引用计数增加过程 弱引用计数的减少过程 弱引用计数减为0 引用计数的减少过程 引用计数减为0 参考文章 本文结合源码讨论

    2024年04月08日
    浏览(36)
  • 【C++】auto_ptr为何被唾弃?以及其他智能指针的学习

    搭配异常可以让异常的代码更简洁 文章目录 智能指针     内存泄漏的危害     1.auto_ptr(非常不建议使用)     2.unique_ptr     3.shared_ptr     4.weak_ptr 总结 C++中为什么会需要智能指针呢?下面我们看一下样例:  在上面的代码中,一旦出现异常那就会造成内存泄漏,什么是内存

    2024年02月11日
    浏览(21)
  • C++11中的智能指针unique_ptr、shared_ptr和weak_ptr详解

    目录 1、引言 2、什么是智能指针? 3、在Visual Studio中查看智能指针的源码实现 4、独占式指针unique_ptr 4.1、查看unique_ptr的源码实现片段 4.2、为什么unique_ptr的拷贝构造函数和复制函数被delete了?(面试题) 4.3、使用unique_ptr独占式智能指针的实例 5、共享式指针shared_ptr  5.1、查

    2024年02月08日
    浏览(29)
  • C++11 新特性 ⑥ | 智能指针 unique_ptr、shared_ptr 和 weak_ptr

    目录 1、引言 2、unique_ptr 3、shared_ptr 4、weak_ptr 5、shared_ptr循环引用问题(面试题)

    2024年02月09日
    浏览(29)
  • 【重学C++】02 脱离指针陷阱:深入浅出 C++ 智能指针

    【重学C++】02 脱离指针陷阱:深入浅出 C++ 智能指针 大家好,今天是【重学C++】系列的第二讲,我们来聊聊C++的智能指针。 在上一讲《01 C++如何进行内存资源管理》中,提到了对于堆上的内存资源,需要我们手动分配和释放。管理这些资源是个技术活,一不小心,就会导致内

    2024年02月05日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包