每个程序的内存空间
- 静态内存:局部static对象,类static数据成员以及定义在函数体外的变量
- 栈内存:函数内的非static变量
- 堆:动态分配(程序在运行时分配的对象,生存期由程序控制)
shared_ptr的使用
//也可以使用auto shared_ptr<string> p = make_shared<string>(10, '9');
每个shared_ptr都有一个关联的计数器,一旦变为0则会释放对象。
使用动态内存的原因:
- 程序自己不知道需要多少对象
- 程序不知道所需对象的准确类型
- 程序需要在多个对象间共享数据
使用智能指针,在拷贝的时候拷贝智能指针,能保证原来的对象不被销毁,因为指针的计数器没有为0,同时也只是拷贝指针无须复制一遍数据。
不要混合使用智能指针和内置指针。如果智能指针和内置指针指向相同的对象,一旦智能指针的计数器为0,对象就被销毁。内置指针变为空悬指针,不可再使用。
不要使用get(p.get())初始化另一个智能指针或为智能指针赋值,否则这两个指针指向相同对象但是是不关联的,会导致delete两次(分别计数器为0)。
reset的使用
shared_ptr<string> p = make_shared<string>(10, '8'); shared_ptr<string> q = p; if (!p.unique()) { p.reset(new string(*p)); //因为有两个指针指向相同对象,所以拷贝一份再修改值。 } *p = "zhougb3"; cout << *p << " " << *q << endl;
删除器函数:p指向的对象释放时,将执行指定函数。防止在函数中间崩溃时对象消失但无法执行指定操作。p指向的对象不是动态分配的,不需要delete。
void end_connection(connection * p){} int main() { connection c; shared_ptr<connection> p(&c, end_connection); }
unique_str拥有指定的对象,不支持拷贝或赋值操作。但在函数的return位置可以返回,因为编译器知道要返回的对象即将被销毁。
unique_ptr<string> p(new string("zhougb3"));
weak_ptr的作用:不会影响一个给定对象的生命周期,也可以阻止用户访问一个不再存在的对象。
智能指针和动态数组
int main() { unique_ptr<int[] > up(new int[10]); up.release(); // 和其他不一样,这里会自动delete,但是如果不是动态数组是不会delete的,指针为空但是原来对象还在。 shared_ptr<int> sp(new int[10], [](int * p) {delete[] p; }); sp.reset();//释放 }
使用allocator类的原因:
- new在一开始时就得创建大量对象,有些对象我们可能到时用不了。
- 在创建时就已经初始化,之后的改变都是赋值
- 对于某些没有默认构造函数的类就没办法动态分配了。
用法
int main() {
int n = 5;
allocator<string> allo;
auto const p = allo.allocate(n);//先分配内存
auto q = p;
allo.construct(q++, "hi");//*q为字符串"hi",q指向下一个位置
}