C++ make_shared使用

C++内存分四大块

  1. 全局 主函数运行前使用,初始化

  2. 静态 变量第一次使用前,初始化
    以上两块内存都会在程序结束后自动释放

  3. 堆区 由程序员管理,C++管理方法有new delete等关键字

  4. 栈区 由编译器管理,存放程序的局部变量和参数

因此我们需要关注堆区的内存管理。内存管理经常会碰到忘记释放造成的内存泄露。
在C++中引入了智能指针,有shared_ptr,unique_ptr和weak_ptr。

shared_ptr

工作中shared_ptr用得比较多,今天做个总结
使用智能指针,需要引入头文件,shared_ptr顾名思义是多个指针指向一块内存。
被管理对象有一个引用计数,这个计数记录在每个指针上,几个shared_ptr指向它,这个数字就是几,当没有任何shared_ptr指向它时,引用计数为0,这时,自动释放对象。
其功能在于当所有指针都释放(或是不再指向对象)的时候,自动释放对象

即,当一个所有指向这块内存的指针生命周期结束时,这块内存会被释放
智能指针的唯一作用,就是自动delete对象,即C++11的新特性,内存管理机制。
智能指针既然会自动delete对象,我们就不能再去手动delete对象了,否则,也会发生多次释放的问题

例:

#include <iostream>
#include <memory>
 
class Test {
public:
    // 无参构造函数
    Test();
    // 有参数的构造函数
    explicit Test(int a);
    // 析构函数
    ~Test();
};
 
Test::Test() {
    std::cout << "无参构造函数" << std::endl;
}
 
Test::Test(int a) {
    std::cout << "有参构造函数,a=" << a << std::endl;
}
 
Test::~Test() {
    std::cout << "析构函数" << std::endl;
}
 
int main(int argc, const char * argv[]) {
    auto p1 = new Test; // 划分堆空间
    std::shared_ptr<Test> sp(p1); // 创建智能指针
    std::cout << sp.use_count() << std::endl; // 打印引用计数
    {
        std::shared_ptr<Test> sp2(sp); // 创建另一个智能指针
        std::cout << sp.use_count() << std::endl; // 打印引用计数
    } // sp2生命周期结束,sp引用计数减1
    std::cout << sp.use_count() << std::endl; // 打印引用计数
    
    return 0;


执行结果

无参构造函数
1
2
1
析构函数

make_shared的引入

一个坑


int main(int argc, const char * argv[]) {
    auto p1 = new Test; // 划分堆空间
    std::shared_ptr<Test> sp(p1); // 创建智能指针
    std::shared_ptr<Test> sp2(p1); // 创建另一个智能指针
    
    return 0;
    }

这段程序会抛出异常 double free detected

new关键字返回的是对应的指针类型。

此处用了两个智能指针管理同一块内存,因为sp 和sp2不知道彼此的存在,所以也会重复释放。

同一个对象只能用同一套内存管理体系,如果它已经有智能指针了,那么再创建智能指针时,需要通过原来已有的指针创建,而不能重复用原始空间来创建。

STL库提供了make_shared函数,其原型为

template <typename T, typename ...Args>
std::shared_ptr<T> std::make_shared(Args && ...args)

官方鼓励用make_shared函数来创建对象,而不要手动去new,这样就可以防止我们去使用原始指针创建多个引用计数体系。

int main(int argc, const char * argv[]) {
    auto sp = std::make_shared<int>(); // 分配堆空间,创建智能指针
    auto sp2 = sp; // 创建另一个智能指针
    
    return 0;
}

参考
https://blog.csdn.net/fl2011sx/article/details/103941346

  • 38
    点赞
  • 169
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
`std::shared_ptr` 和 `std::make_shared` 是 C++11 引入的智能指针相关的类和函数,它们用于管理动态分配的内存资源。下面是一些使用注意事项: 1. 避免循环引用:`std::shared_ptr` 使用引用计数来管理资源,当资源的引用计数为0时,资源会被释放。如果存在互相引用的情况(循环引用),资源将永远无法被释放,导致内存泄漏。因此,在设计和使用 `std::shared_ptr` 时,要避免循环引用。 2. 不要在 `std::make_shared` 中传递裸指针:`std::make_shared` 是一个工厂函数,用于创建并初始化一个动态分配的对象,并返回一个指向该对象的 `std::shared_ptr`。为了避免意外泄漏资源,在使用 `std::make_shared` 时,应该直接传递构造参数而不是裸指针。例如,应该写成 `std::make_shared<T>(args...)` 而不是 `std::make_shared<T>(new T(args...))`。 3. 优先使用 `std::make_shared`:`std::make_shared` 可以在一次内存分配中同时分配对象和控制块(用于存储引用计数等信息)。这可以减少内存碎片并提高性能。所以,除非有特殊需求,推荐优先使用 `std::make_shared`。 4. 注意在多线程环境下的使用:`std::shared_ptr` 的引用计数是线程安全的,但对象的访问不是。在多线程环境下,需要考虑对象的并发访问问题,避免导致数据竞争和未定义行为。 5. 避免将不同的智能指针类型混合使用:`std::shared_ptr` 是一种线程安全的共享所有权的智能指针,而 `std::unique_ptr` 则是一种独占所有权的智能指针。将这两种不同类型的智能指针混合使用可能会导致问题,如编译错误或未定义行为。在需要共享所有权时,优先使用 `std::shared_ptr`。 总之,使用 `std::shared_ptr` 和 `std::make_shared` 可以帮助我们更方便地管理动态分配的内存资源,但在使用时需要注意上述事项以确保正确和高效地使用它们。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值