理解C++变量的作用域和生命周期
C++中变量的作用域和生命周期是一个非常关键的概念,它们从两个维度上考虑了变量在C++代码中的生存范围。作用域就是指变量可以访问的范围,生命周期是指变量逻辑上存在的执行周期。在C++代码中,通常以大括号来指定一个作用域,所有在大括号内定义的变量在定义后可以被访问,退出这段区域后,大括号内的变量逻辑上被销毁而不可访问。作用域可以嵌套定义,内层作用域可以访问外层作用域顺序上已经定义的变量,反之则不可。另外在C++中还有一些特殊的作用域与变量,如全局作用域,全局作用域在程序执行周期一直存在,不需要用大括号声明,如果一个变量定义不存在于任意一个大括号内,则视为全局变量,命名空间,命名空间是C++为了更好的管理变量而引入的;命名空间由关键字namespace声明,它相当于一个全局变量的子集,命名空间内可以写入和全局作用域一样的代码,任意代码也可以访问其中的资源,但同时需要加上该命名空间的前缀;静态变量是一种特殊的局部变量,它在程序运行周期一直存在不会被销毁,但访问限制同其他作用域内的限制一直,如果一个全局的变量或者函数由static关键字声明,则表示该资源只能被当前文件的代码段访问,即外部文件不能用extern的方式进行访问。
void ScopeTest() { int a = 0; { int a = 1; { static int a = 2; a++; printf("Current a is %d ", a); } printf("Current a is %d ", a); int b = 3; printf("Current b is %d ", b); { a++; b++; } printf("Current b is %d ", b); printf("Current a is %d ", a); } printf("Current a is %d ", a); }
输出结果:
理解堆栈两种内存的申请释放方式
分配方式
栈由程序控制自动申请或释放。
程序代码通过显式的malloc/free进行释放。
内存分配区域
栈在内存上是一段连续的空间,分配上和数据结构栈一致,采用先进后出的方式,一个程序在运行开始时会指定一段指定大小的栈空间,超出这段空间会抛出栈溢出的错误,这段栈空间的大小由编译器与系统共同决定。
堆在内存上是呈现碎片时的,在早期的操作系统上,由于一段数据区域需要连续存储,系统会保存一个有空闲区域的链表,来查询是否存在一段区域大于分配需要的空间,现在内存经过了分页式改进,对于碎片化的内存区域在逻辑上任然是连续的。
访问方式
栈上存放数据全部为程序中定义的变量,右值同样会在栈上进行存储,代码可以直接访问栈上的左值。
堆上存放的数据只能通过指针进行访问,栈上会存放一个指针指向一个堆中的地址,代码通过对这个指针变量进行取地址操作来访问堆中的数据。
其他
栈的分配由程序自动控制,并且在一段连续的空间里进行操作,相比堆来说更安全,效率更好。
堆的数据由程序员手工分配释放,在程序的生命周期丢失了未释放的内存指针,就会造成内存泄露,堆的访问需要访问页,效率不如栈。
void StackHeapTest() { int a; // stack int* b; // stack char c[] = "StackHeapTest"; // stack int *d = (int*) malloc(sizeof(int) * 5); // heap free((void*) d); // heap }
unique_ptr和shared_ptr
unique_ptr
1.一个unique_ptr不分享它的指针。它不能被复制到另一个unique_ptr,不能按值传递给一个函数,也不能应用在任何需要复制操作的标准模板库(STL)的算法上。
2.一个unique_ptr只能被移动。这意味着,存储器资源的所有权被转移给另一个unique_ptr,原始的unique_ptr不再拥有所有权。
3.我们在使用中最好限制一个所有权拥有者只能拥有一个对象,,因为多种所有制增加了程序逻辑的复杂性。
4.当我们需要一个智能指针指向一个普通的C ++对象,可以使用unique_ptr,当我们构建unique_ptr时,可以使用make_unique辅助函数。
shared_ptr
1.shared_ptr是一种应用在C+ +标准库专为场景中可能同时有多个所有者来管理内存中对象的寿命的智能指针。
2.初始化一个shared_ptr后,你可以复制它,通过函数参数传值,将其分配给其他shared_ptr的实例。
3.所有shared_ptr实例指向同一个对象,共享访问“控制块”。
4.当有新的智能指针加入、退出或是复位,控制块计数器做出相应改变。
5.当控制块引用计数达到零,则控制块中删除相应的内存资源还有它本身。
split URL
代码:
vector<string> split(const string& s){ const std::tr1::regex separator("[.]|/|(://)"); const std::tr1::sregex_token_iterator endOfSequence; vector<string> result; std::tr1::sregex_token_iterator token(s.begin(), s.end(), separator, -1); while(token != endOfSequence) { result.push_back(*token++); } return result; }
运行结果: