当前位置: 首页 > C/C++, cpp > 正文

c++ 学习笔记之动态内存管理

c++ 的动态内存管理是个大坑,寒假差点害死我。

动态内存与智能指针

智能指针是一个模板,使用的时候必须指定类型。

shared_ptr<string> pl;

shared_ptr<list<int>> p2;

它的使用方式与普通指针类似。解引用一个智能指针返回它指向的对象

make_shared 函数

这是最安全的分配函数,属于标准库。此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr.

shared_ptr<int>  p3 = make_shared<int>(42);

shared_ptr<string> p4 = make_shared<string>(10,9);

shared_ptr<int> p5 = make_shared_ptr<int>();

以上都是正确的初始化方法。

也可以使用一个通用的类型来保存结果

auto  p6 = make_shared<vector<string>>( );

shared_ptr 的拷贝和赋值

我们可以认为每个智能指针都有一个关联容器,通常称其为引用计数。

当用一个智能指针初始化另一个智能指针的时候,或将它作为一个参数传递给一个函数以及作为函数的返回值时,它所关联的计数器就会递增。

当我们给智能指针赋予一个新值或是它被销毁时,计数器就会递减。

一个例子:

auto  r = make_shared<int> (42);

r = q;

r 指向的int 已经被释放了。

ps: 我们关注的点应该在智能指针在恰当的时候自动释放,而不是计数器的实现。

shared_ptr 自动销毁所管理的对象

当指向一个对象的最后一个shared_ptr 被销毁时,shared_ptr类会自动销毁这个对象。

shared_ptr 还会自动释放相关联的内存

只要shared_ptr 指向的内存不再有引用计数就会被消除,即使时函数传递,但是在正常情况下它肯定会销毁,但是就会浪费内存。

注意如果在容器中,容器被重排,一定要手动清除多余元素。

使用了动态生存期的资源的类

一般有以下的三种原因:

1.程序不知道自己需要多少对象

2.程序不知道所需要对象的准确类型

3.程序需要在多个对象之间共享数据

使用动态内存的一个常见原因时允许多个对象共享相同的状态。

使用NEW 的初始化问题

string *ps1  =  new  string;             初始化默认为空的string

string *ps    =  new  string( );          值初始化为空string

int *pi1       =  new  int ;                 默认初始化;值是为定义的

int *pil2      =   new int();                值初始化为0,*pi2 为0

值初始化的内置类型对象有良好定义的值,而默认初始化的对象的值则是未定义的,对与类中那些依赖于编译器合成默认构造函数的内置类型成员,如果它们未在类内初始化,那么他们的值也是未定义的。

可以使用auto 来使它自己推出初始化类型,但是参数必须是一个才行。

auto    p2  = new  auto(obj);

p2  = *typeof(obj);

使用new 动态分配const 对象是合法的。

const  int * pci = new const int (1024);

对与有默认构造函数的可以隐式的声明,其它的必须显示的声明。

内存耗尽

一般会抛出异常,建议使用一个参数来阻止这个异常,只要返回一个空指针,就好。

int  *p2  =  new  (nothrow)  int;   /*这种new 又叫定位new*/

释放delete 相关:

释放的必须是一个指针,且是动态分配的指针,当然可以释放一个NULL 指针。

ps: 由内置指针管理的动态内存在被显示释放前一直都会存在。

使用new 和 delete 的一些问题:

1.忘记delete 内存

2.使用已经释放掉的对象

3.同一块内存释放两次

4.制造这些麻烦总是比修正这些问题简单的多

空悬指针:释放内存后,指针无效了,但是还被用。

野指针: 未初始化的指针。

shared_ptr 和 new 结合使用

不能将一个内置指针隐式转换成一个智能指针,必须使用直接初始化形式。包括返回值的情况。默认情况下,一个用来初始化智能指针的普通指针必须指向动态内存,智能指针默认使用delete 释放所关联的对象。

传参方式:

传参的时候考虑到数据的共享,所以传参的时候应当传递一个存在智能指针,以使它进行拷贝工作,保证函数结束后,这便内存继续存在,不应该传递一个临时对象,更不应该使用内置指针来访问智能指针指向的内存。

*****永远不要使用get初始化另一个智能指针。*******

在发生异常的时候,智能指针可以正确且合理的释放内存,但是直接管理的内存却不会释放内存。

特别的使用智能指针来管理连接这种网络库,我们可以方便的关闭连接,析构函数会自动释放资源。并且我们可以增加自己的释放操作函数。

void  f (destination & d){

connection c = connect(&d);

shared_ptr<connection> p (&c ,end_connection);  /*这样即使是我们异常退出,也能正常释放我们的资源*/

}

 

使用智能指针的一些规范:

1.不使用相同的内置指针初始化多个智能指针

2.不使用delete get( ) 返回的指针

3.不使用get( ) 初始化或reset 另一个智能指针

4.如果使用了get( ) 返回的指针,记住当最后一个对应的智能指针被销毁后,这个返回的指针就无效了。

5.如果使用智能指针管理的资源不是new 分配的内存,记住传递给它一个删除器

unique_ptr  指针

某个时刻只能有一个unique_ptr 指向一个给定的对象,当这个指针被销毁的时候,它所指向的对象也被销毁。并且必须采取直接初始化的形式。它不支持普通的拷贝或赋值操作。

unique_ptr<string> p1(new string(“string”));     /*正确*/

unique_ptr<string> p2(p1);                             /*错误,不支持拷贝*/

unique_ptr<string> p3;

p3 = p2;                                                     /*错误,不支持拷贝*/

不过我们可以使用它的.reset .release 方法转移所有权

当使用release 来转移控制权的时候,会切断unique_ptr 和它原来管理的对象联系,它会返回的指针通常来被初始化一个智能指针或给另一个智能指针赋值。但是在对象将要被销毁的情况下会执行一种特殊的拷贝。

当我们创建一个weak_ptr 时,要用一个shared_ptr 来初始化它.

new 分配动态数组

下面是一些实例:

int * pia  = new int[10] ;         10个为初始化的int

int *pia2 = new int[10]( );      10个值初始化为0的int

string *psa = new string[10];   10个空string

string *psa2 = new string[10]( );  10个空string

注意:我们可以定义一个长度为0的数组

 

 

 

 

本文固定链接: http://zmrlinux.com/2016/03/05/c-%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%e4%b9%8b%e5%8a%a8%e6%80%81%e5%86%85%e5%ad%98%e7%ae%a1%e7%90%86/ | Kernel & Me

该日志由 root 于2016年03月05日发表在 C/C++, cpp 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: c++ 学习笔记之动态内存管理 | Kernel & Me