22、【C++】C++11新特性:智能指针/STL容器

本文详细介绍了C++11中的智能指针,包括auto_ptr、shared_ptr、unique_ptr和weak_ptr,重点讨论了它们的作用、应用场景以及如何解决循环引用问题。此外,还讲解了C++11新增的STL容器,如forward_list、unordered_map和array,分析了它们的特点和使用场景。
摘要由CSDN通过智能技术生成
C++11新特性:智能指针/STL容器

一、智能指针

    1、auto_ptr指针

    2、shared_ptr指针

    3、unique_ptr指针

    4、weak_ptr指针

    5、weak_ptr指针解决循环引用

    6、智能指针的设计和实现

二、STL新容器

    1、C++11 STL容器分类

    2、array

    3、forward_list

    4、unordered_map/unordered_set

    5、begin/end

一、智能指针

    C++程序设计中使用堆内存是非常频繁的操作,堆内存的申请和释放都由程序员自己管理。程序员自己管理堆内存可以提高了程序的效率,但是整体来说堆内存的管理是麻烦的,C++11中引入了智能指针的概念,方便管理堆内存。使用普通指针,容易造成堆内存泄露(忘记释放),二次释放,程序发生异常时内存泄露等问题等,使用智能指针能更好的管理堆内存。

理解智能指针需要从下面三个层次

    (1)从较浅的层面看,智能指针是利用了一种叫做RAII(资源获取即初始化)的技术对普通的指针进行封装,这使得智能指针实质是一个对象,行为表现的却像一个指针。

    (2)智能指针的作用是防止忘记调用delete释放内存和程序异常的进入catch块忘记释放内存。另外指针的释放时机也是非常有考究的,多次释放同一个指针会造成程序崩溃,这些都可以通过智能指针来解决。

    (3)智能指针还有一个作用是把值语义转换成引用语义。C++和Java有一处最大的区别在于语义不同,在Java里面下列代码:

  Animal a = new Animal();
  Animal b = a;

这里其实只生成了一个对象,a和b仅仅是把持对象的引用而已。但在C++中不是这样,

     Animal a;
     Animal b = a;

这里却是就是生成了两个对象。

    简单地说,智能指针只是用对象去管理一个资源指针,同时用一个计数器计算当前指针引用对象的个数,当管理指针的对象增加或减少时,计数器也相应加1或减1,当最后一个指针管理对象销毁时,计数器为1,此时在销毁指针管理对象的同时,也把指针管理对象所管理的指针进行delete操作。

1、auto_ptr指针
    C++11之前的智能指针是auto_ptr,一开始它的出现是为了解决指针没有释放导致的内存泄漏。比如忘了释放或者在释放之前,程序throw出错误,导致没有释放。所以auto_ptr在这个对象声明周期结束之后,自动调用其析构函数释放掉内存。
    int t = 3, m =4; 
    auto_ptr<int> p1(&t); 
    auto_ptr<const int> p2(&m); 
    //注意这里一定是[5]而不是(5),因为(5)表示申请了一个里面存着数字5的地址,
    //不要记混了
    auto_ptr<int> p3(new int[5]); 

    注意:这里只是阐述了怎么用,p1,p2一般不能那么定义,因为一般不用智能指针去指向非堆内存中的地址,因为自行释放非堆地址很有可能出现问题。所以上述程序运行会报错。相当于如下操作:

    int t = 3;
    int *p = &t;
    delete p;

    这样是不行的,运行时候会报错。所以千万不要用一块非new分配的动态内存去初始化一个智能指针。

auto_ptr被弃用的原因

(1)避免潜在的内存崩溃

    智能指针auto_ptr在被赋值操作的时候,被赋值的取得其所有权,去赋值的丢失其所有权。如下面的例子:

    auto_ptr< string> ps (new string ("I reigned lonely as a cloud.");
    auto_ptr<string> vocation; 
    vocaticn = ps;

    执行完上面这步之后,ps就不再指向原来的string串了,变成了空串,vocation指向了原来的string串。但是会出下如下的错误:

 auto_ptr<string> films[5] = 
 {
    
     auto_ptr<string> (new string("Fowl Balls")), 
     auto_ptr<string> (new string("Duck Walks")), 
     auto_ptr<string> (new string("Chicken Runs")), 
     auto_ptr<string> (new string("Turkey Errors")), 
     auto_ptr<string> (new string("Goose Eggs")) 
 }; 
     auto_ptr<string> pwin; 
     pwin = films[2]; // films[2] loses ownership. 将所有权从films[2]转让给pwin,此时films[2]不再引用该字符串从而变成空指针 
     for(int i = 0; i < 5; ++i) 
 	cout << *films[i] << endl;

    以上的程序编译正常,但是运行到输出环节的时候就会出现错误。因为films[2]此时已经丢掉了控制权。而如果用unique_ptr的时候就会在编译期间发现这个错误,因为unique_ptr是不允许直接赋值的。
(2)不够方便–没有移动语义的后果

    比如auto_ptr不能够作为函数的返回值和函数的参数,也不能在容器中保存autp_ptr。

    而这些unique_ptr都可以做到。因为C++11之后有了移动语义的存在,这里调用的是移动构造函数。因为移动语义它可以接管原来对象的资源,同时让原来对象的资源置为空。

    C++11之后智能指针分为了三种:shared_ptr, unique_ptr,weak_ptr,包含在头文件中,而weak_ptr相当于shared_ptr的一个辅助指针, 所以正式的智能指针只有shared_ptr和unique_ptr。

explict关键字

    C++11之后的智能指针的构造函数都有explict关键词修饰,表明它不能被隐式的类型转换。即如下p1的形式是不行的:

shared_ptr<int> p1 = new int(1024); //这种是不行的,
//因为等号右边是一个int*的指针,
//因为有explict修饰,
//所以它不能被隐式的转换为shared_ptr<int>的类型 
shared_ptr<int> p2(new int(1024)); //这种是直接采用了初始化的形式
2、shared_ptr指针

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

    (1)初始化。智能指针是个模板类,可以指定类型,传入指针通过构造函数初始化。也可以使用make_shared函数初始化。不能将指针直接赋值给一个智能指针,一个是类,一个是指针。例如std::shared_ptr p4 = new int(1);的写法是错误的

    (2)拷贝和赋值。拷贝使得对象的引用计数增加1,赋值使得原对象引用计数减1,当计数为0时,自动释放内存。后来指向的对象引用计数加1,指向后来的对象。

    (3)get函数获取原始指针

    (4)注意不要用一个原始指针初始化多个shared_ptr,否则会造成二次释放同一内存

    (5)注意避免循环引用,shared_ptr的一个最大的陷阱是循环引用,循环,循环引用会导致堆内存无法正确释放,导致内存泄漏。循环引用在weak_ptr中介绍。

#include <iostream>
#include <memory>

int main()
{
   
    {
   
        int a = 10;
        //使用make_shared初始化
        std::shared_ptr<int> ptra = std::make_shared<int>(a);
        std::shared_ptr<int> ptra2(ptra); //copy,使得对象ptra的引用次数加1
        std::cout << ptra.use_count() << std::endl;//cout 2

        int b 
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【为什么还需要学习C++?】 你是否接触很多语言,但从来没有了解过编程语言的本质?你是否想成为一名资深开发人员,想开发别人做不了的高性能程序?你是否经常想要窥探大型企业级开发工程的思路,但苦于没有基础只能望洋兴叹? 那么C++就是你个人能力提升,职业之路进阶的不二之选。【课程特色】 1.课程共19大章节,239课时内容,涵盖数据结构、函数、类、指针、标准库全部知识体系。2.带你从知识与思想的层面从0构建C++知识框架,分析大型项目实践思路,为你打下坚实的基础。3.李宁老师结合4大国外顶级C++著作的精华为大家推出的《征服C++11》课程。【学完后我将达到什么水平?】 1.对C++的各个知识能够熟练配置、开发、部署;2.吊打一切关于C++的笔试面试题;3.面向物联网的“嵌入式”和面向大型化的“分布式”开发,掌握职业钥匙,把握行业先机。【面向人群】 1.希望一站式快速入门的C++初学者; 2.希望快速学习 C++、掌握编程要义、修炼内功的开发者; 3.有志于挑战更高级的开发项目,成为资深开发的工程师。 【课程设计】 本课程包含3大模块基础篇本篇主要讲解c++的基础概念,包含数据类型、运算符等基本语法,数组、指针、字符串等基本词法,循环、函数、类等基本句法等。进阶篇本篇主要讲解编程中常用的一些技能,包含类的高级技术、类的继承、编译链接和命名空间等。提升篇:本篇可以帮助学员更加高效的进行c++开发,其中包含类型转换、文件操作、异常处理、代码重用等内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值