第12章 动态内存
动态内存的对象的生存期与它们在哪里创建是无关的,只有当显式地被释放时,这些对象才会销毁。
为了更安全地使用动态对象,标准库定义了两个智能指针类型来管理动态分配的对象。
当一个对象应该被释放时,指向它的智能指针可以确保自动地释放它。
静态内存用来保存局部static对象、类static数据成员以及定义在任何函数体之外的变量。
栈内存用来保存定义在函数体内的非static对象。
分配在静态或栈内存中的对象由编译器自动创建和销毁。
static对象在使用之前分配,在程序结束时销毁。
12.1 动态内存与智能指针
new在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化;
delete接受一个动态对象的指针,销毁该对象,并释放与之关联的内存
为了更容易地使用动态内存,新的标准库提供了两种智能指针类型来管理动态对象。
shared_ptr允许多个指针指向同一个对象
unique_ptr则“独占”所指向的对象
标准库还定义了一个名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。
三种类型都定义在memory头文件中
12.1.1 shared_ptr类
make_shared函数
shared_ptr<int> p3 = make_shared<int>(42);
shared_ptr<string> p4 = make_shared<string>(10, '9');
shared_ptr<int> p5 = make_shared<int>();
shared_ptr的拷贝和赋值
auto p = make_shared<int>(42);
auto p(q);
auto r = make_shared<int>(42);
r = q;
12.1.2 直接管理内存
string *ps = new string;
int *pi = new int;
int *pi = new(1024);
int *ps = new string(10, '9');
vector<int> *pv = new vector<int>{0,1,2,3,4,5,6,7,8,9};
string *ps1 = new string;
string *ps2 = new string();
int *pi1 = new int;
int *pi2 = new int();
auto p1 = new auto(obj);
auto p2 = new auto{a,b,c};
const int *pci = new const int(1024);
const string *pcs = new const string;
传递给delete的指针必须指向动态分配的内存,或者是一个空指针
const对象的值不能被改变,但它本身是可以被销毁的
const int *pci = new const int(1024);
delete pci;
int *p(new int(42));
auto q = p;
delete p;
p = nullptr;
12.1.3 shared_ptr和new结合使用
shared_ptr<double> p1;
shared_ptr<int> p2(new int(42));
我们不能将一个内置指针隐式转换为一个智能指针
shared_ptr<int> p1 = new int(1024);
shared_ptr<int> p2(new int(1024));
shared_ptr<int> clone(int p){
return new int(p);
}
shared_ptr<int> clone(int p){
return shared_ptr<int>(new int(p));
}
12.2 动态数组
int *p = new int[42];
初始化动态分配对象的数组
int *pia = new int[10];
int *pia2 = new int[10]();
string *psa = new string[10];
string *psa2 = new string[10]();
初始化器初始化:
int *pia3 = new int[10]{0,1,2,3,4,5,6,7,8,9};
string *psa3 = new string[10]{"a", "an", "the"};
释放动态数组
delete [] pa; //pa必须指向一个动态分配的数组或为空
typedef int arrT[42]; //arrT是42个int的数组的类型别名
int *p = new arrT; //分配一个42个int的数组,p指向第一个元素
delete [] p; //方括号是必须的,
空悬指针
在delete之后,指针就变成了空悬指针。即指向一块曾经保存数据对象但现在已经无效的内存的指针。
可以在delete之后将nullptr赋予指针,这样就清楚地指出指针不指向任何对象。
12.2.2 allocator类
allocator分配未构造的内存
当我们用完对象后,必须对每个构造的元素调用destroy来销毁它们。
//分配比vi中元素所占用空间大一倍的动态内存
auto p = alloc.allocate(vi.size() * 2);
//通过拷贝vi中的元素来构造从p开始的元素
auto q = uninitialized_copy(vi.begin(), vi.end(), p);
//将剩余元素初始化为42
uninitialized_fill_n(q. vi.size(), 42);
|