1、静态内存和栈内存:静态内存用来保存局部static对象、类static数据成员以及定义在函数之外的变量;栈内存用来保存定义在函数之内的非static对象,分配在静态或栈内存中的对象由编译器自动创建和销毁;对于栈对象,仅在其定义的程序块运行时才存在;static对象在使用之前分配,在程序结束时销毁。
2、除了静态内存和栈内存,每个程序还有一个内存池。这部分空间被称为自由空间或堆。(程序用堆来存储动态分配的对象)。
3、new,在动态内存中为对象分配空间并返回一个指向该对象的指针,可以选择对其进行初始化;delete,接受一个动态对象的指针,销毁对象,并释放与之关联的内存。
4、三种类型指针:shared_ptr允许多个指针指向同一个对象;unique_ptr独占指向的对象。weak_ptr(伴随类),指向shared_ptr所管理的对象。(三种类型都定义在头文件memery中)。
shared_ptr<string> p1;//指向string
shared_ptr<list<int>>p2;//指向int的list
5、默认初始化的智能指针中保存着一个空指针,在一个条件判断中使用智能指针 ,效果就是检测它是否为空。
6、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>();
auto p6 = make_shared<vector<string>>();
7、每个sharedptr都有一个关联的计数器(引用计数),当一个shared_ptr的计数器为0时,它就会自动释放自己所管理的对象。
8、shared_ptr的析构函数会递减它所指向对象的引用计数。如果引用计数变为0,shared_ptr的析构函数就会销毁对象并释放内存。
9、使用动态内存的三种原因:程序不知道需要使用多少对象、程序不知道对象的准确类型、程序需要在多个对象之间共享数据。
StrBlob的ADT接口:
class StrBlob
{
public:
typedef std::vector<std::string>::size_type size_type;
StrBlob();
StrBlob(std::initializer_list<st::string>il);
size_type size() const {return data->size();}
bool empty() const {return data->empty:();}
void push_back(const std::string &t) {data->push_back(t);}
void pop_back();
std::string& front();
std::stirng& back();
private:
std::shared_ptr<std::vector<satd::string>> data;
void check(size_type i , const std:: strign &msg) cosnt;//const成员函数
}
StrBlob的接口实现:
StrBlob::StrBlob():data(make_shared<vector<string>>()){}
StrBlob::StrBlob(initializer_list<string>il):data(make_shared<vector<string>>il){}
void StrBlob::check(size_type i,const string &msg)const
{
if(i>=data->size())
throw out_of_range(msg);
}
string & StrBlob::front()
{
check(0,"front on empty StrBlob");
return data->front();
}
string & StrBlob::back()
{
check(0,"back on empty StrBlob");
return data->back();
}
void StrBlob::pop_back()
{
check(0,"pop_back on empty StrBlob");
data->pop_back:();
}
10、使用new和delete分配,释放动态内存。
11、自由空间分配的内存是无名的,因此new无法为其分配的对象命名,而是返回一个指向该对象的指针。
12、默认情况下,动态分配的对象是默认初始化的。也可以使用直接初始化的方式来初始化一个动态分配的对象。
int * pi = new int(1024);//指向一个初始化了的内存
string *pi= new int;//指向一个未初始化的内存
13、一个动态分配的const对象必须进行初始化。
14、通过delete表达式将动态分配的内存归还给系统,delete表达式接受一个指针,指向我们要释放的对象。
15、由内置指针管理的动态内存在被显示的释放前一直都会存在。
16、野指针:指针操作超越了变量的作用范围;空悬指针:指针指向内存的对象已经被销毁,但是内存还没释放。
16、shared_ptr和new结合使用:
shared_ptr<int> p1= new int (1024);//错误,必须使用直接初始化形式
shared_ptr<int> p2(new int (1024));//直接初始化,正确
17、当一个shared_ptr绑定到一个普通指针时,我们就将内存的管理责任交给了sahred_ptr。(不能使用普通指针访问该内存)
18、get用来将指针的访问权限传递给代码,该代码不能delete该指针指向的内存。
19、当程序执行发生错误时,智能指针指向的内存仍能被正确释放。但是,动态分配的内存就不能被正确释放。
20、智能指针陷阱:
- 不能使用相同的内置指针初始化多个智能指针
- 不能delete get()返回的指针。
- 不使用get初始化或reset另外一个智能指针。
- 使用get()返回的指针时,当最后一个智能指针被销毁时,指针就已经无效了。
- 如果使用智能指针管理的资源不是new分配的对象,需要提供一个删除器。
21、unique_ptr定义时,需要绑定到一个new返回的指针上。且需要直接初始化。
unique_ptr<string> p1(new string("Stegosaurus"));
unique_ptr<string> p2(p1);//错误不支持拷贝
unuque_ptr<string> p3;
p3=p3;//错误不支持赋值
22、不能拷贝或赋值unique_ptr,但可以通过调用release或reset将指针的所有权从一个(非const)unique_ptr转移到另外一个unique_ptr。
unique_ptr <string> p3(new stirng("Trex"));
p2.reset(p3.release());//release释放了原来p2指向的内存空间
23、不能拷贝unique_ptr的规则有一个例外:可以拷贝一个将要被销毁的unique_ptr。
24、unique_ptr默认情况下把delete作为它指向的对象。可以重载unique_ptr中默认的删除器。
25、weak_ptr是一种不控制所指向对象生成期的智能指针,它指向一个由shared_ptr管理的对象。将一个weak_ptr绑定到一个shared_ptr不会改变它的应用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。
auto p = mak_shared<int>(42);
weak_ptr<int> wp(p);//p的引用计数不改变
class StrBlobPtr
{
public:
StrBlobPtr():curr(0){}
StrBlobPtr(StrBlob&a,size_t sz=0):wptr(a.data),curr(sz){}
std::string & deref() const;
StrBlobPtr& incr();
private:
std::shared_ptr<std::vector<std::string>> check(std::size)t,const std::string&) const;
std::weak_ptr<std::vector<std::string>> wptr;
std::size_t curr;
}
std::shared_ptr<std::vector<std::string>>
StrBlobPtr::check(std::size_t i,const std::string &masg) const
{
auto ret = wkptr.lock;()//vector存在吗?
if(!ret)
throw std::runtime_error ("unbound StrBlobPtr");
if(i>=ret->size())
throw std::out_of_range(msg);
return ret ;//
}
26、大多数容器使用标准库容器而不是动态分配的数组。
int *pia = new int[get_size()];
方括号中的大小必须是整型,不必是常量。
27、由于分配的内存并不是数组类型,因此不能对动态数组调用begin或end。也不能用范围for语句来处理动态数组中的元素。
28、默认情况下,new分配的对象都是默认初始化的。
29、不能创建一个大小为0的静态数组对象,但是当n=0时,调用new[n]是合法的。
char arr[0];//错误,不能定义长度为0的数组
char *cp = new char[0];//正确,但cp不能解引用
30、释放动态数组必须用delete[];
31、可以使用unique_ptr来管理动态数组,当unique_ptr指向一个数组时,可以使用下包来范问数组中的元素。
unique_ptr<int []> up (new int[10]);
32、与unique不同,sharedf_ptr不支持管理动态数组。
33、使用shared_ptr管理new分配的内存,使用unique_ptr管理new[]分配的内存。
34、allocator是一个模板,为了定义一个allocator对象。我们必须指明这个allocator可以分配的对象类型。
allocator<string> alloc;
auto const p = alloc.allocate(n);//分配n个未初始化的string
35、allocator分配的内存是未构造的,我们需要在此内存中构造对象。
auto q = p;
alloc.construct(q++);//*q为空字符串
alloc.construct(q++,10,'c');//*q为ccccc
alloc.construct(q++,"hi");//*q为hi
36、用完对象后,必须对每个构造的元素调用destroy来销毁。
while(q!=p)
alloc.destry(--q);
37、一旦元素被毁灭后,就可以重新使用这部分内存保存其它string,也可以释放。
alloc.deallocate(p,n);