程序除静态内存和栈内存,还有自由空间(free store)or 堆(heap)。
使用动态内存容易造成内存泄漏:忘记delete new分配的空间。
share_ptr类:模板。最好用make_shared函数来分配内存。
shared_ptr<int> p1 = make_shared<int> ();
shared_ptr<string> p2 = make_shared<string> (6, '6');
shared_ptr<int> p3(p1);//允许多个指针指向同一个对象,shared
refrence count:比较重要,变为0,自动销毁管理对象,释放相关内存。 拷贝递增,赋新值或销毁时递减,如局部shared_ptr离开其作用域。(注:将shared_ptr存入容器,而后不在需要全部元素,记得erase。)
类使用动态内存:1 不知道自己需要使用多少对象——容器类。 2 不知道对象准确类型。 3 多个对象间共享数据——类成员引用相同的底层数据,只有当引用计数为0时销毁底层数据。
释放一块非new分配内存或者同一内存释放多次,undefined。
然而释放一个空指针总没错:*p0 = nullptr; delete p; //OK
空悬指针(dangling pointer):delete之后,指针任然保存内存地址,即它指向一块曾经保存数据但现在已经无效的内存。最好:
int *p = new int(666); delete p; p = nullptr; //指针置空
但是多指针指向同一内存时要多加小心。
shared_ptr<int> p1 = new int(666);//error:不能将内置指针隐式转换为智能指针
shared_ptr<int> p2(new int(666)); //OK;直接初始化/*特别是在函数返回类型为智能指针时要注意*/
shared_ptr<int> func1(int p)
{ return new int(p);} //wrong!
shared_ptr<int> func2(int p)
{ return shared_ptr<int>(new int(p));}//OK!
void process(shared_ptr<int> ptr)
{//使用ptr
}/*当传递给该函数一个shared_ptr类型参数时,引用计数至少为2*/
shared_ptr<int> p1(new int(666)); //引用计数1
process(p1);//拷贝,函数中引用计数2,p1离开作用域销毁,变为1,并未释放内存,p1仍然指向分配的内存,可继续使用,注意后续处理。/*当传递给该函数一个内置指针时*/
int *p2(new int(666));
process(p2);//error:不能隐式转化
process(shared_ptr<int>(p2));//OK,用完之后引用计数就为0了,内存已经释放!
使用get()时需注意,get()返回指针的代码不能delete此指针,否则原来的shared_ptr将变成空悬指针。不要用get()初始化或为另一个智能指针赋值。
reset():
if (!p.unique()) //检查我们是否是当前对象的唯一用户 p.reset(new int(*p));//不是,分配新的拷贝
//现在是唯一用户,操作p
智能指针确保发生异常时的资源释放:
void func1()
{shared_ptr<int> p1(new int(666));//抛出异常
} //函数结束时,自动释放资源void func2()
{int *p2 = new int(666);//delete之前异常,不会释放资源delete p2;
}
使用智能指针管理的不是new分配的内存,要传递给它一个删除器:
shared_ptr<T> p(i, c);//c是执行析构操作的可调用对象,是我们自定义的删除器
unique_ptr不支持普通的拷贝或赋值操作,可以拷贝或赋值一个将要被销毁的unique_ptr,例如从函数返回一个unique_ptr。注意release()方法并未调用delete。
unique_ptr<int> p1 = new int(666);
p1.release();//并未释放内存,不要这样用
auto p = p1.release();
delete p;//释放了内存
weak_ptr绑定到shared_ptr来观察对象,不改变引用计数,不能用来直接访问对象,因为有可能对象不存在,需调用lock()方法:
shared_ptr<int> p = new int(666);
weak_ptr<int> wp(p);
if (shared_ptr<int> p1 = wp.lock())
{ //lock返回ture,才能进入if语句体通过p1对对象进行操作
}
尽量使用标准库容器而不是动态分配的数组!
分配一个数组,得到的是一个数组元素类型的指针,并非一个数组类型的对象!
int *p = new int [num]();//最好初始化一下
delete [] p;char arr[0] //error:不能定义长度为0的数组
char *cp = new char[0]; //OK,动态分配一个空数组是合法的,//但不能解引用cp
unique_ptr<int[]> p(new int[10]);//unique_ptr直接管理动态数组
p.release();//书上说这里会自动调用delete[],因为管理的是一个数组
shared_ptr<int> p1(new int[10], [](int *p) {
delete [] *p;});
//shared_ptr管理动态数组需传递一个删除器,没有定义[],智能指针不支持指针算术运算,get()内置指针来访问数组元素。
allocator类:分配原始的、未构造的内存,将分配内存与对象构造分离开来,提高灵活性。
allocator<string> alloc; //可以为string对象分配内存
auto p = alloc.allocate(num); //分配num个string对象 //construct()方法构造; //destroy()方法销毁; //deallocate()释放内存;先destroy再释放 //相关算法,copy,fill;