动态分配的内存,只有在显式释放是,这些对象才会销毁。但是标准库中的两智能指针可以确保自动释放。
除了静态内存和栈内存,每个程序还拥有一个内存池。这部分内存被称作自由空间或堆。
静态内存用来保存局部static对象、类static数据成员以及定义在任何函数之外的变量。栈内存用来保存定义在函数没得非static对象。
智能指针:三个类都定义在memory头文件中:
shared_ptr允许多个指针指向同一个对象、
unique_ptr则“独占”所指向的对象。
weak_ptr标准库定义的伴随类,他是一种弱引用,指向shared_ptr所管理的对象。
shared_ptr和unique_ptr都支持的操作:
shared_ptr sp 空智能指针,可以指向类型为t的对象。
unique_ptr up
p 如果在一个判断中使用智能指针,效果就是检测它是否为空。
p 解引用。
p->mem 等价于(*p).mem
返回p中保存的指针。要小心使用,若智能指针释放了其对象,返回的指针所指向的对象也就消失了。
swap(p , q) 交换p 和 q中的指针。
shared_ptr独有的操作:
make_shared(args) 返回一个shared_ptr,指向一个动态分配的类型为t的对象。使用args初始化此对象。
shared_ptrp(q) p是shared_ptr q的拷贝;此操作会递增q中的计数器。q中的指针必须能转换成t*
p = q p和q都是shared_ptr,所保存的指针必须能相互转换。此操作会递减p原来指向对象的引用计数,递增q原来对象的引用计数;若p引用计数变为0,则将其管理的原内存释放。
若为1,饭后true,否则返回false
返回与p共享对象的智能指针数量;可能很慢,主要用于调试。
shared_ptr p3 = make_shared(42); 用其参数构造智能指针,可将前面的类型名改为auto更简单。
如果你忘记了销毁程序中不在需要的shared_ptr,程序仍会正确执行。但会浪费内存。share_ptr在无用之后仍然保留的一种情况是,你将shared_ptr存放在一个容器中,随后重排了容器。
从而不再需要某些元素。这种情况下,应该确保用erase删除那些不需要的shared_ptr元素。
使用动态生存期的资源的类:程序不知道自己需要使用多少对象,程序不知道所需对象的准确类型,程序需要在多个对象间共享数据。
容器类是出于第一中原因而使用动态内存的典型例子。
如果两个对象共享底层的数据,当某个对象被销毁时,我们不能单方面地销毁底层数据。
class strblob
bool empty() const
void push_back(const std::string &t)
void pop_back();
std::string& front();
std::string& back();
pr**ite:
std::shared_ptr> data;
void check(size_type i,const std::string &msg)const;
strblob::strblob():data(make_shared>()
strblob::strblob(initializer_list il) :data(make_shared>(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();
string& strblob::pop_back()
check(0,"pop_back on empty strblob");
return data->pop_back();
front和back应该对const进行重载。
也可以对动态分配的对象进行值初始化,只需在类型名之前后加空括号即可:
int *p1= new int; /默认初始化 *p1的值未定义。
int *p2 = new int();值初始化为0,*p2为0
对于定义了再的构造函数的类类型来说,要求值初始化是么有意义的:不管采用什么形式,对象都会通过默认构造函数来初始化,但对于内置类型有很大的差别。
auto p1 = new auto(obj); p1指向一个与obj类型相同的对象,该对象用obj进行了初始化。
auto p2 = new auto; /错误,括号中只能有单个初始化器。
用new分配const对象时合法的:
const int *p = new const int (1024);
如果内存耗尽。
int *p=new int;//若果分配内存失败,new会抛出std::bad_alloc
int *p=new (nothrow) int; /如果分配失败,new返回一个空指针。
这种形式的new成为定位new,允许我们向new传递额外的参数。nothrow意思是不抛出异常,而是返回以个空指针。
bad_alloc和nothrow都定义在头文件new中。
与new类似,delete表达式也执行两个动作:销毁给定的指针指向的对象,释放对应的内存。
我们传递给delete的指针必须是指向动态分配的内容,或者是一个空指针。释放一块非new分配的内存,或将相同的指针值释放多次,行为都是未定义的,nullptr也只能释放一次,delete一个const动态对象,只要delete指向它的指针即可;
在delete一个指针后,指针值就是无效的了,就变成我们说说的空悬指针,可以再delete后赋值nullptr,但只对于对个指针指向同一个动态内存块是无效的。赋值nullptr只是保证了当前指针,但是别的指针无法抱枕。
我们可以用new来初始化智能指针,:
shared_ptr p (new int(42));
shared_ptr p =new int(42);/错误,接受指针参数的智能指针的构造函数是explicit的。
/同样的,函数返回值也必须如此。
shared_ptr clone(int p) 错。
shared_ptr clone(int p)
默认情况,一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放所关联的对象。(可自己定义)
定义和改变shared_ptr的其他方法。
shared_ptr p(q) p管理内置指针q所指向的对象;q必须指向new分配的内存,且能够转换成t*类型;
shared_ptr p(u) p从unique_ptr u那里接管了对象的所有权;将u置为空。
shared_ptr p(q,d) p接管了内置指针q所指向的对象的所有权。q必须能转换成t*类型,p将使用的调用对象d来代替delete
shared_ptr p(p2,d) p是shared_ptr p2的拷贝,p将用可调用对象来代替delete
若p是唯一的指向其对象的shared_ptr,reset会释放此对象。若传递了可选参数内置指针q,会令p指向q,否则会将p置为空。d来替换delete
当将一个shared_ptr绑定到一个普通指针时,我们就将内存管理的责任交给了这个shared_ptr。一旦这样做了,我们就不应该在使用内置指针来访问shared_ptr所指向的内存了。即,不要混合使用普通指针和智能指针。
智能指针定义了一个get成员函数,返回一个指向智能指针管理对象的内置指针。是为了那些不能传递智能指针的**而设计的。
get用来将指针的访问权限传递给**,你只有在确定**不会delete指针的情况下,才能使用get。特别是,永远不要用get初始化另一个智能指针或者为另一个智能指针赋值。
p=new int(1024) /错误,不能将一个指针赋予shared_ptr
new int( 1024));正确。
与赋值雷系,reset会更新引用计数,如果需要会释放p指向的对象。常用unique一起使用。
if(!string(*p));我们不是唯一用户;分配新的拷贝。
C11学习笔记 5
参数传递时,如果是引用类型,它将绑定到对应的实参上,否者,将实参的值拷贝后赋给形参。引用可避免拷贝,如果不需要改变参数,最好定义成常量引用。和其他初始化一样,当用实参初始化时会忽略顶层const,当形参有顶层const时,传给它常量对象或非常量对象都可以。我们可以用非常量初始化一个底层const对象...
C 11学习笔记 16
tuple是类型pair的模板。不同tuple类型的成员类型也不同,但一个tuple可以有任意数量的成员。每个确定的tuple类型的成员数目是固定的。当我们希望将一些数据组合成单一对象,但有不想麻烦地定义一个新数据结构来表示时,tuple是非常有用的。快速而随意 的数据结构 tuple类型及其伴随类...
C 11学习笔记 15
面向对象编程和泛型编程都能处理在编写程序时不知道类型的情况。不同之处 oop能处理类型在程序运行之前都未知的情况 而泛型编程中,在编译时就能获知类型了。模板参数类别不能为空。模板参数表示在类或函数定义中用到的类型或值。template int compare const t v1 const t v...