C++动态内存new+delete+shared_ptr+unique_ptr

直接管理内存

C++中,动态内存的管理是通过一对运算符来完成的:new+delete。

  • new在动态内存中为对象分配空间并返回一个指向该对象的指针,可以选择对其进行初始化。

  • delete 接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。

new+delete用法

int *pi=new int;//new创建了一个动态的,未初始化的无名对象,返回指向该对象的指针
int *pi=new int(); //,在类型名后跟一对圆括号即代表初始化了。这例初始化0了
string *ps=new string; //初始化为空的string,因为相当于类类型对象将用默认构造函数进行初始化
string *ps=new string(); 

// 支持构造函数用法
string *ps=new string(5,'a');
int *pi=new int(5);
vector<int> *pv=new vector<int>{0,2,3};

// 可以使用auto让初始化器推断对象类型。此方法由于编译器要用初始化器的类型来推断要分配的类型,只有当括号中仅有一初始化器时才可以使用auto
auto p1= new auto(obj);
// auto p2 = new auto{a,b,c}//错误,括号中只能有的那个初始化器

// 动态分配的const对象
const int *pci=new const int(1024);
const string *pcs = new const string;// 类似于其他const对象,动态分配的const对象必须进行初始化。这里的string是隐式初始化了

// 分配销毁数组
int *pa = new int[3];
delete [] pa;
内存耗尽

抛出bad_alloc异常。

int *p1=new int;//若分配失败则抛异常bad_alloc
int *p2=new (nothrow) int;// 若分配失败,new返回一个空指针。意思是不能抛异常
// bad_alloc和nothrow都定义在头文件new中
delete释放动态内存
delete p;//p必须是指向动态分配的内存

int i,*pi1=&i,pi2=nullptr; 
//delete pi1; //未定义:pi1指向一个局部变量

// 释放一个空指针总是没有错误的

//const的指针也是可以销毁的

通常情况下,编译器不能分辨一个指针指向的是静态还是动态的对象。类似地,编译器也不能分辨一个指针所指向的内存是否已经释放了。所以delete表达式,大多数编译器都会编译通过。尽管是错误的

C++11智能指针shared_ptr 、unique_ptr

为了更容易安全地使用动态内存,C++11标准库提供了两种智能指针类型来管理动态对象。智能指针的行为类似于常规指针,重要的区别是它负责自动释放所指向的对象。新标准库提供的这两种智能指针的区别在于管理底层指针的方式:

  • shared_ptr 允许多个指针指向同一个对象
  • unique_ptr 则独占所指向的对象

标准库还定义了一个名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。

这三种类型都定义在memory头文件中。#include<memory>

shared_ptr类

类似vector,智能指针也是模板。

#include <memory>
shared_ptr<string> p1; //可以指向string
shared_ptr<list<int>> p2; //可以指向int的list

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

#include <memory>
shared_ptr<string> p1; 
if(p1 && p1->empty)  // 第一个是p1不为空,第二个是检查指向一个空string
    *p1 = "hi"; // 取内容解引用

下表列出了shared_ptr和unique_ptr都支持的操作

// shared_ptr和unique-ptr都支持的操作
shared_ptr<T> sp // 智能指针,可以指向类型为T的对象
unique_ptr<T> up

p // 将p用作一个条件判断,若p指向一个对象,则为true
*p // 解引用p获得它指向的对象
p->mem // 等价于(*p).mem
p.get() //返回p中保存的指针。要小心使用,若只能指针释放了其对象返回的指针所指向的对象也就消失了。所以尽量不要把裸指针取出来
swap(p,q) // 交换p、q中的指针
p.swap(q) 


// 下面是shared_ptr独有的操作
make_shared<T>(args)//返回一个share_ptr,指向一个动态分配的类型为T的对象。使用args初始化此对象
share_ptr<T>p(q)// p是shared_ptr q的拷贝此操作会递增q中的计数器。q中的指针必须能转换为T*(参见4.11.2 I,第143页)
p=q //p和q都是shared_ptr,所保存的指针必须能相互转换。此操作会递减p的引用计数,递増q的引用计数若p的引用计数变为0,则将其管理的原内存释放
p.unique() //若p.use_count()为l,返回true否则返回false
p.use_count() // 返回与p共享对象的智能指针数量可能很慢,主要用于调试
make_shared 函数

最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准库函数。

此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。

#include <memory>  
shared_ptr<int> p3 = make_shared<int>(42);// 指向一个值为42的int 的shared_ptr
shared_ptr<string> p4 = make_shared<string>(10,'9'); //指向一个值为'999..'的string
    //即传入的形式是与string构造函数符合的
shared_ptr<int> p5 = make_shared<int>(); //指向一个值初始化的int,值为0
 // 不传递任何参数,对象就会进行初始化
 
// 也可以用auto接收
auto p6 = maked_ptr<vector<string>>();

shared_ptr的拷贝和赋值
// 拷贝和赋值时,对个shared_ptr都会记录有多少个其他shared_ptr指向相同的对象
auto p = make_shared<int>(42); // p指向的对象只有p一个引用者
auto q(p);  // p和q指向相同对象,此对象有两个引用者
// 我们可以认为每个shared_ptr都有一个关联的计算器,通常称为 引用计数 reference count
// 每当拷贝一个shared_otr,计数器都会递增。例如当用一个shared)ptr初始化另一个shared_ptr。
// 当shared_ptr赋予一个新值或是shared_ptr被销毁(例如一个局部的shared_ptr离开其作用域),计算器就会递减。为0时,自动释放管理的对象
shared_ptr自动销毁所管理的对象

当指向一个对象的最后一个shared_ptr被销毁时,shared_ptr类就会自动销毁此对象。(通过成员函数:析构函数)

shared_ptr在无用之后仍然保留的一种可能情况是,你将shared_ptr存放在一个容器中,随后重排了容器,从而不再需要某些元素。在这种情况下, 你应该确保用erase删除那些不再需要的shared_ptr元素。

之前使用的类中,分配的资源都与对应对象生存期一致。例如每个vector都拥有自己的元素。当拷贝一个vector时,原vector和副本vector中的元素是相互分离的。

vector<string> v1;//空vector
{// 新作用域
    vector<string> v2 ={"a","b","c"};
    v1=v2;
}//v2被销毁,v1还有三个元素,是原来v2的拷贝。
// 即vector存在,其中元素才会存在。vector都不存在了,其中元素肯定就销毁了。

但某些类分配的资源具有与元对象相独立的生存期。一般而言,如果两个对象共享底层的数据,当某个对象被销毁时,我们不能单方面地销毁底层数据

Blob<string> b1;//空Blob
{// 新作用域
	Blob<string> b2 ={"a","b","c"};
    b1=b2;//
}//b2被销毁,但b2中的元素不能销毁。而b1指向最初由b2创建的元素
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值