C++基础知识

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不需要。

原文地址:https://www.cnblogs.com/wukuaiqian/p/7746594.html