C++ Primer学习总结 第12章 动态内存
1、申请使用shared_ptr
int main()
{
shared_ptr<string> sp;//定义一个智能指针,但是sp现在还没申请空间string s("123");// *sp = s; //无效// cout << *sp;sp = make_shared<string>(3,'a');//在动态内存中分配对象并初始化它cout << *sp << endl;*sp = s;cout <<*sp;return 0;
}
2、shared_ptr 计数
赋值、拷贝、向函数传递一个智能指针,函数返回智能指针都会增加当前智能指针的计数。
void show(shared_ptr<int> sp){
cout << sp.use_count()<<endl; return }int main()
{
shared_ptr<int>sp;//构造空职能指针cout << sp.use_count() << endl;//0sp = make_shared<int>(11);//赋值cout << sp.use_count() << endl;//1;shared_ptr<int> sp1(sp);//拷贝给第二个cout << sp.use_count() << endl;//2;shared_ptr<int> sp2;sp2 = sp;//赋值给第三个cout << sp.use_count() << endl;//3cout << sp2.use_count() << endl;//3show(sp);//作为实参(拷贝)}
3、使用new动态申请内存
默认情况下,new申请的内存对象都是默认初始化的。
int main()
{
int *p1 = new int;//默认初始化cout << *p1 << endl;//随机值int *p2 = new int();//值初始化cout << *p2 << endl;int *p3 = new int(100);//直接初始化cout << *p3 << endl;string *p4 = new string(6,'a');//构造函数初始化cout << *p4 << endl;std::vector<int> *p5 = new vector<int> {
0,1,2,3,4};//列表初始化for(auto x:*p5)cout << x << endl;
}
4、new申请的const对象必须初始化。
申请内置类型,必须用()初始化。如果申请类类型,如果该类对象有默认构造函数,可以默认初始化。如果没有,必须用其他的构造函数初始化。
class A{
public: A(int v):v(v){
}int v;
};
int main()
{
//const int *p1 = new const int;//错误,const必初始化const int *p1 = new const int();cout << *p1 << endl;const string *p2 = new const string;//有默认构造函数cout << *p2;// const A *p3 = new const A;//没有默认构造函数。const A *p3 = new const A(10);cout << p3->v << endl;return 0;
}
5、关于delete.
delete 只能删除指针,且该指针是由new申请的内存空间。
销毁给定指针指向的对象,释放对应的内存。
注意的问题:
1.不要忘记delete,内存永远不会归还给自由空间了。
2.不要使用已经释放掉的内存。
3.不要delete两次,自由空间有可能被破坏。
delete+nullptr一起使用,避免使用空悬指针。
但是仍然保护很有效,因为一个对象有可能被多个指针同时指向。
6、shared_ptr 和 new结合使用
shared_ptr的构造函数是explicit的,必须使用直接初始化形式。
shared_ptr<int> p(new int(1));shared_ptr<int> p = new int(1);//错误,必须直接初始化
7、不要混用智能指针和内置指针。
智能指针绑定到内置指针上时,内存管理就交给智能指针了,一旦这样做了就不要再用内置指针访问了。
下面这段代码在cb上跑竟然指针p还在???
在VS上才成功。(被编译器安排了
void Fun(shared_ptr<int>p){
}
int main()
{
int *p = new int;*p = 10;cout << *p << endl;Fun(shared_ptr<int>(p) );cout << *p << endl;//未定义
}
8、不要用get初始化另一个智能指针或为智能指针赋值,+ 其他操作
(再次被编译器安排,和c++primer P414描述不一样)
void Fun(shared_ptr<int>p) {
}
int main()
{
shared_ptr<int>p(new int(42));int *q = p.get();{
shared_ptr<int>(q);}//wc,,,咋没释放???//Fun(shared_ptr<int>(q));//q被释放cout << *p << endl;
}p.reset(new int(666));
p.unique();//是不是唯一的用户
9、unique_ptr对象初始化
由于unique_ptr “拥有”它的对象,所以不能拷贝和赋值,且只能通过内置指针通过括号()初始化它。
例外:可以用返回值为unique_str的函数去拷贝和赋值一个将要被销毁的unique_str;
unique_ptr<int> f(){
return unique_ptr<int>(new int(22));
}
int main()
{
unique_ptr<int> p1(new int(11));cout << *p1 << endl;unique_ptr<int> p2;// p2 = p1;//错误p2 = f();cout << *p2 << endl;return 0;
}
10、unique_ptr对象的reset() 和 release()函数的用法
int main()
{
unique_ptr<int> p1(new int(1));unique_ptr<int> p2(p1.release());//p1放弃对指针的控制权(并不释放内存),返回指针值cout << *p2 << endl;//1cout << *p1 << endl;//未定义unique_ptr<int> p3(new int(3));cout << *p3 << endl;p3.reset(p2.release());//释放掉自己指针内存,重新控制p2.release()的指针cout << *p3 << endl;//1cout << *p2 << endl;//未定义return 0;
}
11、unique_ptr传递自己的删除器(shared_ptr类似)
对象构造了自己的删除器end_ptr
当对象析构的时候,会执行end_ptr(up中的int 指针)
输出2
void end_ptr(int *p){
cout << *p + 1 << endl;delete p;
}
int main()
{
unique_ptr<int,decltype(end_ptr)*> up(new int (1),end_ptr);
}
12、weak_ptr
不控制对象生存期的智能指针,指向shared_ptr管理的对象。不影响shared_ptr的引用计数。
int main()
{
shared_ptr<int> sp(new int(3));weak_ptr<int>wp;wp = sp;cout << wp.use_count() << endl;//1cout << wp.expired() << endl;//use_count为0返回tureshared_ptr<int> sp2 = wp.lock();//通过weak_ptr获取一个shared_ptr对象cout << wp.use_count() << endl; //2return 0;
}
13、new分配动态数组
使用new分配的数组元素类型的指针 而不是 一个数组类型。
int main()
{
typedef int a[10];int *p1 = new a;int *p2 = new int[3];int *p3 = new int[3]();//p1,p2,p3并不是数组类型cout << *begin(p1);//错误,p1不是数组,只是首元素指针delete [] p1;//释放一个数组return 0;
}
14、使用智能指针管理动态数组注意shared_ptr 和 unique_str的区别
unique_ptr<int[]> up(new int[5]);for(int i = 0;i<5;++i)up[i] = i+1;for(int i = 0;i<5;++i)cout << up[i] << endl;//unique_str支持下标操作shared_ptr<int> sp(new int[5],[](int *p){
delete [] p;});//lambda,必须提供删除器for (int i = 0; i < 5; ++i){
*(sp.get() + i) = i+1;//不支持下标cout << *(sp.get() + i ) << endl;}
15、new 和 malloc的区别
参数:运算符–库函数
返回类型:指针—void* (需转换)
分配失败:异常—NULL
分配内存+初始化(构造函数,)—只分配内存
内存区域:自由存储器—堆区