C++ Primer
动态内存
全局对象在程序启动时分配,程序结束时销毁,局部自动对象,在进入程序块时被创建,离开块时销毁,局部static对象在第一次使用前分配,程序结束时销毁。
显式动态分配的对象,只有显式被释放时才会销毁对象,智能指针确保自动释放它。
静态内存保存局部静态对象,定义在函数之外的变量和类的静态成员,栈内存保存定义在函数内的非静态变量,堆内存保存动态分配的对象
动态内存与智能指针
new
关键字在堆内存中为对象分配空间并返回指向该对象的指针,delete
接受一个动态对象指针,销毁该对象
这类方法极易出错,因为无法确保在正确的时间释放内存,所以定义了两种智能指针:shared_ptr
允许多个指针指向同一对象,unique_ptr
独占指向的对象 weak_ptr
指向shared_ptr
指向的对象。定义在
shared_ptr类
- 智能指针也是模板,所以创建时应当提供额外的信息——指向的类型
shared_ptr<int> p1;
用法与普通指针类似,有-> * 运算符和swap() get()方法,但是有其独有的操作。
独有操作 | 描述 |
---|---|
make_shared<T> (args) |
返回一个指向动态分配的类型为T的智能指针对象 |
shared_ptr<T>p (q) |
p是智能指针q的拷贝,此操作递增了q的计数器 |
p=q |
都是智能指针对象,保存的指针类型必须能够相互转换,此操作递减p的引用计数,递增q的引用技术,如果p的引用计数变为0则释放其管理的原内存 |
p.unique() |
p.use_count() 为1,返回true否则返回false |
p.user_count() |
返回与p共享对象的智能指针数量 |
make_shared()
是最安全的分配和使用动态内存的方法shared_ptr<int> p3=make_shared<int>(42)
当进行拷贝或者赋值时,每个shared_ptr
都会记录有多少shraed_ptr
指向相同的对象,每个shared_ptr
都有一个关联的计数器被称为引用计数,当shared_ptr
被拷贝,如传递参数给函数或者作为函数的返回值,计数器就递增(值传递创建了临时的指针),当给shared_ptr
赋予新值或者销毁,计数器才递减,当计数为0时,自动释放对象shared_ptr
通过析构函数完成对象销毁工作,来释放对象所分配的资源,递减引用计数,为0时销毁对象释放内存- 动态对象不再使用,
shared_ptr
类会自动释放
shared_ptr<Foo> factory(T arg)
{
return make_shared<Foo>(arg);
}
void use_Factory(T arg)
{
shared_ptr<Foo> p=factory(arg);
}//p 离开了作用域,指向的内存自动释放
p是函数内的局部变量,函数块结束自动销毁,此时递减计数器,又因为递减到了0,所以将对象也释放了,如果将shared_ptr
存放在一个容器中,而后重排了容器,要删除不需要的元素,以防浪费内存。
- 一般来说,类对象的资源与生存期一致,比如在两个
vector
之间拷贝元素,两个容器是独立的,但有些类分配的资源有与原对象独立的生存期,不同容器共享相同的底层元素,此时销毁某个对象,分配的资源并不会销毁,因为有可能其他对象还在使用。 - 为了实现不同容器的数据共享,常为每个类对象设置一个shared_ptr来管理同一个容器,记录有多少个类对象共享同一个vector并在最后一个使用者被销毁时释放vector
class StrBlob
{
public:
typedef vector<string>::size_type size_type;
StrBlob();
StrBlob(initializer_list<string