C++ primer 第五版个人笔记 第十二章 动态内存

程序用堆来存储动态分配的对象(即那些在程序运行时分配的对象),动态对象的生存期由程序来控制,当其不再使用时,我们的代码必须显式地销毁他们;

12.1 动态内存与智能指针

  1. C++中动态内存的管理是通过一对运算符new和delete来完成的,new在动态内存中为对象分配空间并返回一个指向该对象的指针,delete接受一个动态对象的指针并销毁该对象释放与之关联的内存;
  2. 新标准库提供两种智能指针管理动态对象,与常规指针的区别在于它负责自动释放所指向的对象;shared_ptr允许多个指针指向同一个对象,unique_ptr则“独占”所指向的对象,weak_ptr是一种弱引用,指向shared_ptr所管理的对象,这三种类型都定义在<memory>头文件中;
  3. shared_ptr类的操作详见401页,最安全的分配和使用动态内存你的方法是调用一个名为make_shared的标准库函数,类似顺序容器的emplace成员函数,make_shared用其参数来构造给定类型的对象,如果不传递任何参数,对象就会进行值初始化;
    auto p6 = make_shared<vector<string>>(); p6指向一个动态分配的空vector<string>

    我们可以认为每个shared_ptr都有一个关联的计数器,通常称其为引用计数,当拷贝一个shared_ptr(拷贝构造的三种情况)时计数器递增,当给shared_ptr赋予一个新值或者shared_ptr被销毁(例如一个局部的shared_ptr离开作用域)时,计数器递减;

    // factory函数返回一个shared_ptr指针,指向<Foo>类型的对象
    shared_ptr<Foo> factory(T arg)
    {
        return make_shared<Foo>(arg);
    }
    
    shared_ptr<Foo> use_factory(T arg)
    {
        shared_ptr<Foo> p = factory(arg);    //p计数为1
        return p;    //return p使得p引用计数递增了一次,及时P离开作用域递减一次p的计数仍不为0,因此不会释放其内存
    }

     

  4.  由于在最后一个shared_ptr销毁前内存都不会释放,因此需要保证shared_ptr在无用之后就不再保留,否则会浪费内存,有一种情况是shared_ptr保存在一个容器中,容器重排后不再需要全部元素,要用erase删除那些不在需要的shared_ptr元素;  

  5.  

    程序使用动态内存主要有三个原因:程序不知道自己有多少个对象,程序不知道所需对象的准确类型,程序需要多个对象间共享数据;    

  6. 将一个shared_ptr赋予另一个shared_ptr会递增赋值号右侧shared_ptr的引用计数,而递减左侧的引用计数。如果shared_ptr的引用计数变为0,它所指向的对象会被自动销毁。    

  7. 如果提供了一个括号包围的初始化器,可以用auto从此初始化器来腿短我们想要分配的对象的类型,但是只能有单一初始化器时才可以使用auto;

    auto p1 = new auto(obj) ; //可以,p指向与obj同类型的对象
    auto p2 = new auto{a,b,c} ; //错误,括号中只能有单个初始化器

      

  8.   new后面可以传递额外的参数,这种形式的new为定位new,传递(nothrow)表示告诉它不能抛出异常,如果这种形式的new不能分配所需内存,它会返回一个空指针;

  9.  当delete一个指针后,指针值就变为无效,但很多机器上指针仍然保存着(已经释放了的)动态内存的地址,这时候这种指针就是所谓的空悬指针(dangling pointer);有一种方法可以避免空悬指针的问题,在指针即将要离开其作用域之前释放掉它所关联的内存;如果需要保留指针,可以在delete之后将nullptr赋予指针,这样就清楚地指出指针不指向任何对象;

  10. 如果不初始化一个只能指针,它就会被初始化为一个空指针,也可以用new返回的指针初始化智能指针,智能指针的构造函数是explicit的(说明只能直接初始化不能使用=拷贝初始化),同时一个返回shared_ptr的函数不能在其返回语句中隐式转换一个普通指针;

  11. 智能指针定义了一个名为get的函数,它返回一个内置指针,指向智能指针管理的对象,该指针虽然是一个内置指针但是不能用delete删除;永远不要用get初始化另一个智能指针或者为另一个智能指针赋值;

  12. 自己定义释放操作以及智能指针5个陷阱,详见417页;

  13. unique_ptr “拥有”它指向的对象,只能有一个unique_ptr指向一个给定的对象,unique_ptr不支持普通的拷贝与赋值操作

    unique_ptr<string>p1(new string("stegosaurus"));
    unique_ptr p2(p1); //错误,不支持拷贝
    unique_ptr p3 = p2; //错误,不支持赋值

     

12.2 动态数组

  1. 使用new分配对象数组要在类型名后使用方括号如下所示:

    int *pia = new int[get_size()];  //get_size()确定对象数目,必须是整型但不必是常量
    
    typedef int arrT [42] ;  //arrT表示 int[42]类型,即一个有42个int的数组
    int *p = new arrT; 

    对于这里new int[]的理解,不能认为是分配了一个数组对象,而是得到一个数组元素类型的指针,指向第一个int元素 

     

  2.  动态数组不是数组类型,不能对动态数组调用begin或end,这些函数使用数组维度来返回指向首元素和尾后元素的指针。出于相同的原因,也不能用范围for语句来处理动态数组中的元素;

  3.  

     动态分配一个空数组是合法的, char *cp = new char[0]; 正确但是cp不能解引用;此时cp保证与new返回的其他任何指针都不相同,就像尾后指针一样; 

  4. 为了释放动态数组,需要在数组名前加上一个空方括号对; delete[] pa; pa必须指向一个动态分配的数组或为空;数组中的元素按逆序销毁,即最后一个元素首先被销毁,然后倒数第二个,以此类推;

12.3 文本查询程序

  1. 重点弄清楚shared_ptr在这个程序里的用途

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值