动态内存与智能指针
C++中动态内存的分配是在堆中进行的,主要通过下面3个方面:
1.new和delete
new和delete很常见,new运算符分配内存,并且同时调用对象的构造函数,delete释放内存,并且调用对象的析构函数,但是new 和delete管理内存需要手动分配和释放内存,然而在程序中很难选择适当的时机释放内存,所以C++又引入了智能指针。
delete释放内存时候需要注意的问题:
(1)必须释放由new运算符分配的内存
(2)同一块内存不可以释放多次
(3)可以释放指向nullptr的指针
(4)释放内存结束后应该将指向该内存的指针置为nullptr
2.智能指针
智能指针和常规指针的重要区别就是它可以自动释放所指向的对象,常见智能指针有如下3种:
(1)shared_ptr
它允许多个指针指向同一个对象,他有一个计数器,用来保存该对象的指针数,当拷贝一个shared_ptr指针时,该指针的计数器+1,当一个我们给shared_ptr赋一个新值或者shared_ptr被销毁时候,计数器-1,只有当计数器为0的时候,才会释放该shared_ptr指向的内存。
shared_ptr独有的操作:
make_shared<T>(args) 返回一个shared_ptr,指向类型T的对象,args为初始化参数(自动调用该对象的构造函数来初始化)
例:shared_ptr<int> ptr=make_shared<int>(10) //指向一个初始值为10的int的shared_ptr
shared_ptr<T> p(ptr) p是ptr指针的一个拷贝,ptr的计数器+1 注:下面的unique_ptr指针不能拷贝初始化,因为unique_ptr只能有一个指针占有
p=q p和q所保存的指针必须能相互转化,p的计数器-1,q的计数器+1
p.use_count() 表示p共享对象的智能指针数量
p.unique() 表示p共享对象的智能指针数量是否为1,是则返回true,否则返回false
(2)unique_ptr
只能有一个指针指向对象,当unique_ptr被销毁时,它所指向的对象也被销毁
它的初始化一般结合new进行:
例:unique_ptr<string> p(new string("hello"));
unique_ptr常用操作:
u.release() 放弃u对对象的控制权,返回指针,u为nullptr
u.reset() 释放u所指向的对象
u.reset(p) 将u指向内置指针p所指向的对象
初始化的时候虽然不能使用拷贝或赋值,但可以使用release或者reset将指针的所有权从一个unique转移到另一个unique
例如:unique_ptr<string> p1(p2.release()); //p2被初始化为p1原来保存的指针,p1置为空
p2.reset(p1.release()) //将p1的所有权转交给p2,p1置为空
(3)weak_ptr
它指向一个shared_ptr指针所指向的对象,但是不会改变shared_ptr计数器,同样,shared_ptr计数器为0的时候,即使有weak_ptr指向对象,该对象还是会被释放,这就是弱共享对象的特点,它同样使用make_shared<T>来初始化
3.allocator
特点:new将内存分配和对象构造组合到了一起,而allocator将他们分离开了
用allocator分配内存主要经历下面几个步骤:
(1)声明allocator对象
allocator<int> all;//可以分配int的对象
(2)分配空间(未构造)
auto const p=all.allocate(n)//分配n个未初始化的int
(3)构造对象
all.construct(p,4);//构造一个值为4的对象
(4)销毁对象
all.destory(--p);//调用对象的拷贝构造函数,该对象必须已经构造
(5)释放内存
all.deallocate(p,n);//必须在destory之后,p必须是allocate返回的指针,n必须为p创建时要求的大小