1.迭代器
iterator(迭代器)模式又称Cursor(游标)模式,用于提供一种方法顺序访问一个聚合对象中的各个元素,而又不需暴露该对象的内部表示。
由于迭代器的以上特性:与聚合对象耦合,在一定程度上限制了它的广泛运用,一般仅用于底层聚合支持类,如stl中list、vector、stack等容器类以及ostream_iterator等扩展iterator。
2.迭代器与指针的区别
迭代器不是指针,是类模板,表现得像指针。它只是模拟了指针的一些功能,通过重载了指针的一些操作符:-> * ++ – 等。迭代器封装了指针,是一个“可遍历STL容器内全部或部分元素”的对象,本质是封装了原生指针,是指针概念的一种提升,提供了比指针更高级的行为,相当于一种智能指针,它可以根据不同类型的数据结构来实现不同的++ 和–等操作。
迭代器返回的是对象引用而非对象的值,所以只能输出*取值后的值而不能直接输出其自身。
3.迭代器产生的原因
iterator类的访问方式就是把不同集合类的访问逻辑抽象出来,似的不用暴露集合内部的结构而达到循环遍历集合的效果。
在C++中,可以使用struct和class定义类,都可以继承。区别在于:struct的默认继承权限和默认访问权限都是public,而class的默认继承权限和访问权限都是private。此外,class还可以定义模板类形参,比如:template
右值引用是C++11中引入的新特性,它实现了转移语义和精确传递。它的主要目的有两个方面:
1.消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率。
2.能够更简洁明确地定义泛型函数。
左值和右值的概念:
左值:能对表达式取地址、或匿名对象/变量。一般指表达式结束后依然存在的持久对象。
右值:不能对表达式取地址,或匿名对象。一般指表达式结束就不在存在的临时对象。
右值引用和左值引用的区别:
1.左值可以寻址,而右值不可以
2.左值可以被赋值,右值不可以被赋值,可以用来给左值赋值
3.左值可变,右值不可变(仅对基础类型适用,用户自定义类型右值引用可以通过成员函数改变)
详细可参考这里
resize既分配了空间,也创建了对象,可以通过下标访问。当resize的大小
reserve只修改capacity大小,不修改size大小,resize既修改capacity大小,也修改size大小。
reserve是容器预留空间,但并不真正创建元素对象,在创建对象之前,不能引用容器内的元素,因此当加入新的元素时,需要用push_back()/insert()函数。
resize是改变容器的大小,并且创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。
resize和reserve接口的共同点是它们都保证了vector的空间大小(capacity)最少达到它的参数所指定的大小。
需要注意的是:
对于resize,假如resize的大小为n,那么:
如果n比当前的vector元素数目要小,vector的容量要缩减到resize的第一个参数大小,既n。并移除那些超出n的元素同时销毁他们。
如果n比当前vector元素数目要大,在vector的末尾扩展需要的元素数目,如果第二个参数val指定了,扩展的新元素初始化为val的副本,否则按类型默认初始化。
注意:如果n大于当前的vector的容量(是容量,并非vector的size),将会引起自动内存分配,会很耗时。
在C++中,虚拟内存分为代码段、数据段、BSS端、堆区、栈区、文件映射区六部分。
段错误通常发生在访问非法内存地址的时候,具体来说分为以下几种情况:
内存泄漏是指由于疏忽或错误造成了程序未能释放掉不再使用的内存的情况。
内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成的内存浪费。
内存泄漏分类:
C++11的可变参数模板,对参数进行了高度泛化,可以表示任意数目、任意类型的参数,其语法为:在class或typename后面带上省略号。
比如:
Template<class ... T>
void func(T ... args)
{
cout << "num is" << sizeof ...(args) <<endl;
}
func() //args不含任何参数
func(1) // args包含一个int类型的实参
func(1,2.0) //args包含一个int和一个double类型的实参
其中T叫做模板参数包,args叫做函数参数包
省略号的作用如下:
C++可以使用递归的函数的方式展开参数包,获得可变参数的每个值。通过递归函数展开参数包,需要提供一个参数包展开的函数和一个递归终止函数。
比如:
#include
using namespace std;
void print()
{
cout << "empty" << endl;
}
template <class T,class ... Args>
void print(T head,Args ... args)
{
cout << head << "," ;
print(args...);
}
int main()
{
print(1,2,3,4);
return 0;
}
输出:1,2,3,4,empty
参数包Args…在展开的过程中递归调用自己,每调用一次参数包中的参数就会少一个,直到所有参数都展开为止,当面没有参数时就会调用非模板函数print终止递归过程。
在单核机器上写多线程程序,仍然需要线程锁。
因为线程锁通常用来实现线程的同步和通信。在单核机器上的多线程程序,仍然存在线程同步的问题。因为在抢占式操作系统中,通常为每个线程分配一个时间片,当某个线程时间片耗尽时,操作系统会将其挂起,然后运行另一个线程。如果这两个线程共享某些数据,不使用线程锁的前提下,可能会导致共享数据修改引起冲突。
多进程模型的优势是CPU,多线程模型主要优势为线程间切换代价较小。
因此多线程适用于I/O密集型的工作场景,因为I/O密集型的工作场景经常会由于I/O阻塞导致频繁的切换线程。同时, 多线程模型也适用于单机多核分布式场景。
多进程模型,适用于CPU密集型。同时,多进程模型也适用于多机分布式场景中,易于多机扩展。