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;//0
sp = 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;//3
cout << sp2.use_count() << endl;//3
show(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;//1
cout << *p1 << endl;//未定义
unique_ptr<int> p3(new int(3));
cout << *p3 << endl;
p3.reset(p2.release());//释放掉自己指针内存,重新控制p2.release()的指针
cout << *p3 << endl;//1
cout << *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;//1
cout << wp.expired() << endl;//use_count为0返回ture
shared_ptr<int> sp2 = wp.lock();//通过weak_ptr获取一个shared_ptr对象
cout << wp.use_count() << endl; //2
return 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
分配内存+初始化(构造函数,)—只分配内存
内存区域:自由存储器—堆区