动态内存与智能指针

智能指针与常规指针的区别在于它自动释放所指向的对象。
shared_ptr:允许多个指针指向同一个对象
unique_ptr:“独占”所指向的对象。
weak_ptr:伴随类,弱引用,指向shared_ptr所管理的对象。

shared_ptr

//定义,与vector类似,智能指针也是模板
shared_ptr<string> p1;
shared_ptr<list<int>> p2;

make_shared函数:最安全的分配和使用动态内存的方法,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。

//定义一个智能指针p3,指向值为42的int。
shared_ptr<int> p3=make_shared<int>(42);
//指向一个值初始化的int
shared_ptr<int> p4=make_shared<int>();

可认为每个shared_ptr有一个关联计数器,通常称为引用计数。

auto p=make_shared<int>(42);//p指向的对象之一p一个引用
auto q(p);//q,p指向同一个对象,此对象有2个引用
auto r=make_shared<int>(42);
r=q;//递增q的引用计数,递减r的引用计数,r原来的对象已经没有引用者,会自动释放
shared_ptr<Foo> factory(T arg)
{
    //其他操作
    return make_shared<Foo>(arg);
}
void use_factory(T arg)
{
    shared_ptr<Foo> p=factory(arg);
}//p离开了作用域,它指向的内存会被自动释放掉

程序使用动态内存的三个原因:

  • 程序不知道自己需要使用多少对象
  • 程序不知道所需对象的准确类型
  • 程序需要在多个对象间共享数据

定义strBob类实现共享数据

class strBob
{
public:
    typedef vector<string>::size_type size_type;
    strBob();
    strBob(initializer_list<string> il);
    size_type size()const {return data->size();}
    bool empty()const{return data->empty();}
    void push_back(const string &t){data->push_back(t);}
    void pop_back();
    string &front();
    string &back();
private:
    shared_ptr<vector<string>> data;
    //如果data[i]不合法,抛出异常
    void check(size_type i,const string &msg)const;
}
strBob::strBob():data(make_shared<vector<string>>()){}
strBob::strBob(initializer_list il)
data(make_shared<vector<string>>(il)){}
void strBob::check(size_type i,const string &msg)const
{
    if(i>=data->size)
    throw out_of_range(msg);
}

直接管理内存

int *p1=new int;//默认初始化,*p1的值未定义
int *p2=new int();//值初始化为0
auto p3=new auto(obj);//p指向一个与obj同类型的对象

用new分配const对象是合法的

const int *p=new const int(1024);//一个动态分配的const对象必须初始化,对于定义了默认构造函数的类类型,可以隐式初始化,其他必须显示初始化。
int *p1=new int;//如果分配失败,抛出异常
int *p2=new(nothrow) int;//如果分配失败,new返回一个空指针,这种new称为定位new

shared_ptr和new

shared_ptr p1=new int(1024);//错误,接收指针参数的智能指针参数是explicit的,因此无法将常规指针隐式转换成智能指针,所以只能直接初始化
shared_ptr p2(new int(1024));//正确

unique_ptr

当我们定义一个unique_ptr时,需要将其绑定到一个new返回的指针上,初始化unique_ptr必须采用直接初始化

unique_ptr p1;
unique_ptr p2(new int(42));

由于unique_ptr“独占”对象,因此不支持拷贝和赋值。

unique_ptr<string> p2(p1.release());//将对象所有权从p1转为p2
p2.reset(p3.release());////将对象所有权从p3转为p2,同时reset释放了p2原来的内存

unique_ptr因此不能拷贝有个例外,可以拷贝或赋值一个即将要被销毁的unique_ptr

unique_ptr<int> clone(int p)
{
    return unique_ptr(new int(p));
}

weak_ptr

weak_ptr是一种不控制对象生存期的智能指针,它指向shared_ptr 管理的对象,且不会改变shared_ptr的引用计数。被销毁的对象即使有weak_ptr指向对象,还是会被销毁。

auto p=make_shared<int>(42);
weak_ptr<int> wp(p);//wp弱共享p

lock检查weak_ptr指向的对象是否存在。

if(shared_ptr<int> np=wp.lock())//如果不为空,条件成立
{
    //np与wp共享对象
}

动态数组

int *pia=new int[get_size()];//pia指向第一个int
typedef int arrT[42];
int *p=new arrT;
delete p;//释放一个动态分配的对象
delete []p; //释放动态数组

unique_ptr管理动态数组

unique_ptr<int[]> up(new int[10]);//
for(size_t i=0;i!=10;i++)
{
    up[i]=i;//不能使用点和箭头的成员运算符,可以通过小标访问数组元素
}
up.release();//自动调用delete销毁其指针

shared_ptr不直接支持管理动态内存,如果希望shared_ptr管理动态数组,必须为其提供自己定义的删除器

shared_ptr<int> sp(new int[10],[](int *p){detele []p;})
sp.reset();//调用我们提供的lambda释放数组
//shared_ptr未定义下标运算符,并且不支持指针的算术运算符
for(size_t i=0;i!=10;++i)
    *(sp.get()+i)=i;//使用get获得一个内置指针

allocator类将内存分配和对象构造分开,它分配的内存是原始的,未构造的。alloctor是一个模板

allocator<string> alloc;
auto const p=alloc.allocte(n);
auto q=p;
alloc.construct(q++);
alloc.construct(q++,10,'c');
alloc.construct(q++,"hi");//一定要在构造之后使用内存
while(q!=p)
    alloc.destroy(--q);//销毁对象
alloc.deallocate(p,n);//释放内存
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值