C++智能指针的工厂函数

  1. std::make_unique 用于创建 std::unique_ptr 实例
  2. std::make_shared 用于创建 std::shared_ptr 实例

目录

1. make_unique

2.make_shared 


1. make_unique

std::make_unique 是一个 C++14 中引入的函数模板,用于创建 std::unique_ptr 实例。它的目的是简化创建动态分配对象的过程,并且提供了更好的异常安全性。在使用 std::make_unique 时,你只需提供要动态分配的对象的类型和构造函数参数,函数会返回一个包装了这个动态分配对象的 std::unique_ptr

#include <iostream>
using namespace std;
class Person
{
public:
    Person()
    {
        cout << "构造函数" << endl;
    }
    Person(int, int)
    {
        cout << "构造函数" << endl;
    }
    ~Person()
    {
        cout << "析构函数" << endl;
    }
};
void test()
{    
    // 使用默认构造
    unique_ptr<Person> up1 = make_unique<Person>();
    // 使用有参构造
    unique_ptr<Person> up2 = make_unique<Person>(10, 20);
    // 创建对象数组
    unique_ptr<Person[]> up3 = make_unique<Person[]>(3);
}
int main()
{
    test();
    return 0;
}

由于 make_unique 函数调用对象的默认构造函数创建对象数组。所以,类内需要提供默认构造函数,否则无法使用

make_unique 函数和 unique_ptr 构造函数创建智能对象时的区别是什么呢?

1. 从语法角度:make_unique 函数比 unique_ptr 语法更加简洁
2. 从安全角度:make_unique 是异常安全的,而 unique_ptr 构造函数创建方式则不是。

异常安全性是指当函数在执行过程中发生异常时,程序依然能够保持数据结构的一致性和资源的正确释放。对于 make_unique,它保证了在异常发生时内存会被正确释放,即使在内存分配后抛出异常也不会导致内存泄

#include <iostream>
#include <memory>
using namespace std;
class Person
{
public:
    Person()
    {
        cout << "Person 构造函数" << endl;
    }
    ~Person()
    {
        cout << "Person 析构函数" << endl;
    }
};
void do_logic(unique_ptr<Person> uq, int number) {}
int get_number()
{
    cout << "get_number" << endl;
    throw exception();
    return 100;
}
int main()
{
    try
    {
        // 1. 构造函数 异常不安全
        do_logic(unique_ptr<Person>(new Person), get_number());
        // 2. make_unique 异常安全
        // do_logic(make_unique<Person>(), get_number());
    }
    catch (...)
    {
        cout << "错误处理..." << endl;
    }
    return 0;
}

结果发现析构函数没有执行,就会造成内存泄漏,不会构造,在windows和gcc执行的结果不同,就是说在不同的编译器,代码执行的顺序是不一样的,先去执行get_number函数,不会进行new的操作。

2.make_shared 

make_shared 是 C++ 标准库提供的一个函数模板,用于创建并返回一个 std::shared_ptr,它与 new 操作符相比具有更好的性能异常安全

class Person
{
public:
    Person(int, int) 
    {
        cout << "无参构造函数" << endl;
    }
    ~Person()
    {
        cout << "析构函数" << endl;
    }
};
void test()
{
    shared_ptr<Person> sp = make_shared<Person>(10, 20);
}

注意make_shared 函数并不支持创建用于管理动态对象数组的 shared_ptr 对象,这个和 make_unique 是有区别的

当创建 sp 对象时,过程如下:

  1. 首先,在堆上创建 Person 动态对象,需要分配一次内存。
  2. 然后,在堆上创建引用计数对象,需要分配一次内存。
  3. 最后,在栈上创建 shared_ptr 对象。

从上面过程来看,很显然,我们需要为 Person 动态对象、引用计数对象动态分配两次内存

而当使用 make_shared 函数时:

  1. 一次性分配 Person 动态对象和引用计数对象所需要的内存,并在该内存中构建 Person 对象和引用计数对象。
  2. 然后,在栈上创建 shared_ptr 对象。

从该过程中,我们发现 make_shared 函数会比 shared_ptr 构造函数创建方式减少一次动态内存的申请和释放,进而提升了 shared_ptr 的构建效率

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值