码迷,mamicode.com
首页 > 其他好文 > 详细

第12章 动态内存

时间:2015-11-29 23:08:55      阅读:260      评论:0      收藏:0      [点我收藏+]

标签:

全局对象:启动时分配,结束时销毁

局部对象:程序块内分配,程序块外销毁

static对象:第一次使用分配,结束时销毁

动态内存使用new来分配对象,使用delete销毁对象

12.1两种智能指针

#include<memory>

shared_ptr: 多个指针可以指向同一个对象

unique_ptr: 独占指向的对象

        weak_ptr: 一个伴随类,指向shared_ptr管理的对象,是弱引用

 

智能指针也是模板,定义时需要指明类型

shared_ptr<string> p1;

shared_ptr<list<int>> p2;

默认初始化为空指针

shared_ptr和unique_ptr都支持的操作

unique_ptr<T> up

shared_ptr<T> sp

空智能指针,指向类型为T的对象

p

作为一个条件判断,指向一个对象则为true

*p

解引用,获得指向的对象

p->item

等价于(*p).item

p.get()

返回p中保存的指针

swap(p, q)

p.swap(q)

交换p和q中的指针

 

shared_ptr独有的操作

make_shared<T>(args)

返回一个shared_ptr,使用args初始化T的对象

shared_ptr<T> p(q)

p是q的拷贝,指向同一个对象,q中计数器递增

p=q

递减p中引用计数,递增q中引用计数

p.unique()

如果p.use_count()为1,返回true

p.use_count()

返回p共享对象的智能指针的数量,很慢,用于调试

 

使用动态内存的三种原因

  1. 程序不知道需要使用多少对象
  2. 程序不知道所需对象的准确类型
  3. 程序需要在多个对象间共享数据

12.1.2直接管理内存

int *ptr = new int; //默认初始化,值未定义
int *ptr1 = new int();//值初始化为0
int *ptr2 = new int(1024); 
const int *ptr3 = new const int(1024);
int *ptr4 = new (nothrow) int(1024);//分配失败,不抛出bad_alloc异常,而是返回空指针
string *str = new string; //默认初始化为空string
string *str1 = new string();//值初始化为空string
string *str2 = new string("string");
vector<int> *pv = new vector<int>{ 1, 2, 3, 4, 5 };
auto p = new auto("123");//为const char**
auto p = new auto(string("123"));//为string*

int i, *pi1 = &i, *pi2 = nullptr;
double *pd = new double(33), *pd2 = pd;
delete i;  // 错误,i不是指针
delete pi1; // 未定义,pil是一个局部变量
delete pd;  // 成功
delete pd2; // 未定义,pd2已经被释放
delete pi2; // 成功,释放了一个为空的指针

释放内存之后,指针变成了悬空指针(dangling pointer),通常仍然指向原来的内存地址,如果之后再次delete,会破坏自由空间内存,通常需要重新赋予nullptr。

12.1.3结合使用shared_ptr和new

shared_ptr<int> p2 = new int(42);// 错误int*不能隐式转换成智能指针
shared_ptr<int> p2(new int(42));// 正确,因为构造函数是explicit,上边才不成立
int* q = new int(10);
shared_ptr<int> p(q, [](int* p) {cout << *p; delete p; });// 自定义释放内存的方法

不建议结合使用

 

其他操作

shared_ptr<int> p(new int(9)); 
int *pi = p.get();// 得到内置指针
if (!p.unique())//不是唯一引用
    p.reset(new int(*p + 1));//改变p的指向,不影响其他引用的值
*p = *p + 1;//唯一引用,直接改变也不影响其他的了

 

12.1.4智能指针与.Net using

void f(destination &d)
{
    connection c = connect(&d);
    //保证在程序结束后释放c
    shared_ptr<connection> p(&c, [](auto c) {delete c; });
    ...
}

 

12.1.5独占智能指针unique_ptr

unique_ptr不能进行赋值、拷贝操作

unique_ptr<int> u;
u = nullptr;//释放u的对象,并置空
u.release();//释放u的对象控制,并返回内置指针,置空u
u.reset();//释放u的对象
u.reset(q);//指向q,释放u的对象

可以拷贝和返回一个将要被销毁的unique_ptr例如参数返回时的拷贝,这其实是一种特殊的拷贝(13.6.2)。

自定义删除器需要在定义时指明类型,这与shared_ptr作为参数不同。

unique_ptr<int, decltype(process)*> u(new int(10), process);

 

12.1.6弱智能指针weak_ptr

weak_ptr将会绑定到一个shared_ptr,它不会改变shared_ptr的引用计数。

弱智能指针需要用shared_ptr对象初始化。

shared_ptr<int> u1(new int(50));
weak_ptr<int> w = u1;
w.reset();// 置空w
w.use_count();//共享shared_ptr的数量
w.expired();//user_count为0,返回true,否则为false
w.lock();//返回对应的一个shared_ptr对象,如果expired为true,则返回的是空的对象
if (shared_ptr<int> u = w.lock())//可以判断并得到shared_ptr

 

12.2动态数组

最好使用vector、string等其他标准库中的容器,这些标准库可以使用默认版本的拷贝、赋值和析构操作,而使用动态数组,就需要自己考虑了。

12.2.1数组的new

int *pia = new int[10];//10个未初始化
int *pia1 = new int[10]();//10个值初始化为0
int *pia2 = new int[10]{ 1,2,3 };//前三个为1,2,3,其他的为0

 

  1. 需要注意的是,分配的内存空间并不是数组类型空间,而仅仅是内存空间,并且返回一个首地址。
  2. 使用new分配的对象,执行默认初始化。

 

释放时需要用到

delete[] pia;

对于释放时delete中如何知道内存中的大小,一般的编译器是通过在分配的动态数组前记录分配的内存的大小,然后释放的时候读取记录进行释放。

 

使用智能指针管理动态数组

unique_ptr<int[]> u(new int[10]);
cout << u[10] << endl;
u.release();//可以自动调用delete []

shared_ptr<int> sp(new int[10], [](int*p) {delete[] p; });//需要自定义销毁函数
sp.reset();//使用自定义销毁函数

shared_ptr不直接支持动态数组管理,所以也不支持下标运算和指针的算术运算,需要使用时,必须使用get获取内置指针。

allocator<T> a

定义一个为T类型对象分配内存的allocator对象

a.allocate(n)

为n个T类型对象分配内存

a.deallocate(p, n)

收回为n个T类型对象分配的内存

a.construct(p, args)

在p指向的位置构造T对象(需要一个一个构造)

a.destroy(p)

销毁p指向位置的T对象(需要一个一个销毁)

int count = 10;
allocator<string> a;
//分配内存
string* p = a.allocate(count);
for (int i = 0; i < count; i++)
    a.construct(p + i);//构造对象
for (int i = 0; i < count; i++)
    a.destroy(p + i);//销毁对象
//收回内存
a.deallocate(p, count);

 

uninitialized_copy(b,e,b2)

从迭代器b到e的范围中的对象,内拷贝到b2内存中

uninitialized_copy_n(b,n,b2)

从迭代器b开始的n个元素拷贝到b2内存中

uninitialized_fill(b,e,t)

在b到e的范围中创建t的拷贝

uninitialized_fill_n(b,n,t)

在b开始的n个元素内存中,创建t的拷贝

 

第12章 动态内存

标签:

原文地址:http://www.cnblogs.com/qiusuo/p/5005727.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!