1.bind()
函数对象:可以以函数方式与()结合使用的任意对象,包括 function 仿函数、函数名、函数指针、含有()操作符的类对象。
function是一组函数对象包装类的模版,(又叫仿函数)实现一个泛型的回调机制,function< int( int, int)>形式,可调用的对象普通函数、函数指针、lanmbda表达式、函数对象和类的成员函数等。
int add(int i, int j){ return a + b;} auto mod = [](int a, int b){ return a%b;} struct divide{ int operator()(int i, int j){ return i/j; } }; function<int(int, int)> func1 = add; function<int(int, int)> func2 = mod; function<int(int, int)> func3 = divide; func1(1, 2); int a = func2(1, 2); func3(1, 2);
//bind template <class Fn, class... Args> /* unspecified */ bind (Fn&& fn, Args&&... args);
bind返回一个和Fn功能相同,但参数是Args(已经填好了,调用时不用传参了)和占位符的函数对象,如果Fn是成员函数,则返回值第一个参数this指针。
struct integer{ int i; integer(int i):i(i){} void incr_by(int j) {i += j;} }; integer x(0); integer* y = &x; using namespace std::placeholders; auto f0 = bind(&integer::incr_by, _1, _2); f0(x, 2); //x.incr_by(2); x.i = 2; f0(y,2);//y->incr_by(2); x.i = 4; auto f1 = bind(&integer::incr_by, x, _1); f1(2); //这里x是值传递,调用的是一个临时对象的incr_by函数,x的i不改变。 auto f2 = bind(&integer::incr_by, ref(x), _1); f2(2);//引用,x改变了,x.i = 6; auto f3 = bind(&integer::incr_by, &x, _1); f2(2);//指针,x改变了,x.i = 8;
2.vitual
c++在布局以及存取时间上主要的额外负担是vitual引起的,因此在真的需要运行时多态,才用虚函数(注意:必须是基类类型的指针或引用才触发动态绑定)。
vitual函数:用于支持“执行期绑定”,以实现多态。 vitual继承: 用于实现类似菱形继承中的基类只有一个单一被共享的实体(A->B->D;A->C->D;vitual继承,则D中只有一个A的实体)。
有虚函数的类在创建对象时,在构造函数中先生成一个虚函数表,表里依次存放所有虚函数的地址,生成的对象中有一个虚函数指针指向虚函数表。
而生成派生类对象时,会先调用基类的构造函数,生成一个基类的虚函数表,然后调用派生类的构造函数,会覆盖虚函数表中同名的函数,从而实现多态(这就是c++里的动态连编:在程序运行时选择调用哪个函数)。
而函数隐藏的目的则是:使父类的改动不会影响子类重载的调用
3.const用法
I.代替宏定义,定义常量
II.const * 常量指针。 与 * const 指针常量。
III.修饰函数返回值,常用在返回值为用户自定义类型。
IV.修饰函数参数(一般为指针、引用),使得 非const 和 const类型(一般为值传递的临时对象)都能作为实参调用。
V.在类中,修饰成员函数,反正()后面,表明此函数不能改变对象的成员变量,const对象只能调用const成员函数。
4.内存管理
c++动态内存可能出现的问题:
I.内存泄露,new/delete 和 malloc/free 没有配套使用,或者在构造函数中new了之后抛出异常,就不会执行析构函数中的delete。
解决方法:用智能指针代替new/delete管理对象,注意shared_ptr和 unique_ptr的区别(unique_ptr无法复制构造和赋值操作,但可以移动构造和移动赋值(如作为函数返回值)), 在遇上环形引用(类A中有类B的智能指针引用对象,类B中有类A的智能指针引用对象,两个都有一个对方的引用计数,无法析构)时使用一个weak_ptr。
II.野指针,指针未初始化且未指向null 或 指向一个已删除的对象(如函数体内局部对象,或delete后未置null),则指针会随机指向一块内存,很可能是本程序中已使用的内存或数据,如果此时通过此指针对该内存写操作,可能造成程序崩溃或数据污染,(且野指针难以发现,危害大)。
解决方法:初始化时置null,释放时置null。
III.内存碎片,频繁的使用new/malloc,由于所申请的内存大小不定而造成内存碎片。
解决方法:内存池,在使用内存之前,先申请分配一定数量大小相同的内存块组成的内存池作备用,当有新的内存需求时,就从内存池分出一部分内存块,若内存块不够再申请新的内存。
5.new/delete 和 malloc/free 比较
I.new/delete 是c++运算符(运算符是编译器控制的,因此可以重载),malloc/free 是标准c库函数,不受编译器控制。
II.malloc只负责申请一块一定长度的内存,而new不仅分配了内存,还进行了sizeof,类型转换,类型安全检查,还调用了构造函数,delete调用了析构函数。
III.malloc/free需要库文件支持,而new/delete不需要。