不调用C/C++ 的字符串库函数,编写strcpy

char * strcpy(char * strDest,const char * strSrc)
{
    if (strDest==NULL||strSrc==NULL)
        return NULL;
    char * strDestCopy=strDest; //make a copy of original char *strDest
    while ((*strDest++=*strSrc++)!='\0');
    // *strDest = '\0'; //不需要这一句
    return strDestCopy;
}​

手撕strcmp

https://www.cnblogs.com/jeakeven/p/5855553.html

volatile关键字

volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。简单地说,就是防止编译器对代码的优化。

mutable关键字的作用

mutable定义的数据成员,可以在const成员函数中进行修改。

explicit关键字

explicit关键字的作用就是防止类构造函数(仅有一个实参,它不是默认参数)的隐式自动转换,将参数自动转换为类对象的标识符。

A a=10;
//相当于直接调用A a = A(10);

操作符operator重载

重载的运算符是具有特殊名字的函数:他们的名字由关键字operator和其后要定义的运算符号共同组成。和其他函数一样,重载的运算符也包含返回类型、参数列表及函数体。

重载运算符函数的参数数量与该运算符作用的运算对象数量一样多。一元运算符有一个参数、二元运算符有两个参数。当一个重载的运算符是成员函数时,this绑定到左侧运算对象。成员运算符函数的(显式)参数数量比运算对象的数量少一个。

对于一个运算符函数来说,要么它是类的成员,要么至少含有一个类类型的参数:

//错误:不能为int重定义内置的运算符
int operator+(int, int);​

这一约定意味着当运算符作用于内置类型的运算对象时,我们无法改变该运算符的含义。

只能重载已有的运算符,不能发明新的运算符号,如operator**。

C++对象的内存布局、C++中的虚函数(表)实现机制

https://blog.twofei.com/496/

vtable是编译器在编译时期为我们创建好的, 只存在一份,存储在static data segment

继承机制中对象之间是如何转换的?

存在继承关系的类型之间的转换规则:
1)从派生类向基类的类型转换只对指针或引用类型有效。
2)基类向派生类不存在隐式类型转换。
3)和任何其他成员一样,派生类向基类的类型转换也可能会由于访问受限而变得不可行。
基类向派生类的显式类型转换参考dynamic_cast。

对于派生类向基类的类型转换的可访问性,有以下三种情况:(假设D继承自B)
1)只有当D共有的继承自B时,用户代码才可以使用派生类向基类的转换,否则,不可以使用。
2)不论D以何种方式继承自B,D的成员函数及友元都可以使用派生类向基类的转换。
3)如果D继承自B的方式是公有的或受保护的,则D的派生类的成员和友元可以使用D向B的类型转换,否则,不能使用

继承机制中引用和指针之间如何转换?

基类——>派生类:用dynamic_cast转换,首先检查基类指针(引用)是否真正指向一个派生类对象,然后再做相应处理,对指针进行dynamic_cast,成功返回派生类对象,失败返回空指针,对引用进行dynamic_cast,成功返回派生类对象,失败抛出一个异常。
派生类——>基类:可以用dynamic_cast或者直接进行类型转换(直接赋值)。

虚函数,虚函数表里面内存如何分配?

https://blog.csdn.net/best_fiends_zxh/article/details/59111761

https://blog.twofei.com/496/#simu

多继承时,指针的自适应偏移。

https://www.nextptr.com/question/a6212602/base-pointer-offset-adjustment-for-multiple-inheritance

任何试图使用父类指针想调用子类中的未覆盖父类的虚成员函数的行为都会被编译器视为非法,即使父类指针真的指向了子类对象。

如何实现只能动态分配类对象,不能定义类对象?(这个牛客上的题目,我把如何只能动态分配和只能静态分配都讲了一下)

静态分配:A a,由编译器创建类对象,在栈上分配内存。

禁止静态分配:如果类的析构函数在类外部无法访问,则编译器拒绝在栈空间上为类对象分配内存。所以只要把析构函数声明成private的即可。如果需要继承,则声明成protected的。(注意,把构造函数声明成private的话,动态分配也无法进行). add = delete after desctructor

动态分配:使用运算符new来创建一个类的对象,在堆上分配内存。

禁止动态分配:因为动态分配一定要通过new,因此只要重载operator new,将其声明成private或protected就好。

在执行main函数之前,都会执行哪些操作

https://www.cnblogs.com/weilf/p/4157213.html
https://www.cnblogs.com/fushi/p/7631359.html

内存溢出有那些因素?

new在堆上分配了太多内存,导致堆out of memory

通常栈空间容量比较小,一般是1MB~2MB,所以体积比较大的对象不适合在栈中分配。特别要注意递归函数中最好不要使用栈对象,因为随着递归调用深度的增加,所需的栈空间也会线性增加,当所需栈空间不够时,便会导致栈溢出,这样就会产生运行时错误。

异常机制是怎么回事?

关键词:

栈展开:当一个异常被抛出时,沿着调用链的块将依次退出直至找到与异常匹配的处理代码

栈展开过程中对象自动销毁(局部变量)

异常对象(exception object)

http://www.cnblogs.com/qq329914874/p/6739592.html

迭代器

使得我们可以在不知道对象内部表示的情况下,按照一定顺序(由iterator提供的方法)访问聚合对象中的各个元素。

该类型的迭代器只能读取容器中的元素,不能用于改变其值。

STL容器中,在迭代器删除元素时会发生什么?

可能发生迭代器失效

容器的插入insert和erase操作可能导致迭代器失效,对于erase操作不要使用操作之前的迭代器,因为erase的那个迭代器一定失效了,正确的做法是返回删除操作时候的那个迭代器。

必须在构造函数初始化式里进行初始化的数据成员有哪些?

1:const数据成员;
2:引用数据成员;
3:没有默认构造函数的数据成员(有默认构造函数的话,编译器会自动调用。如果没有的话,就需要手动指定构造函数,否则该成员无法产生)
4:如果基类没有默认构造函数,派生类必须手动调用基类的特定的构造函数来完成基类部分的构造。

C++ 位操作

操作的时候要考虑有符号数(signed number)和无符号数(unsigned number)。

对于有符号数:左移的时候右侧补0;右移的时候左侧补符号位(正数符号位为0,则补0;负数符号位为1,则补1).

对于无符号数:左移的时候右侧补0;右移的时候左侧也是补0.

判断二进制数的末位是否为0,可以用 n & 1 == 1

C++11特性

auto自动类型推断

lambda表达式

https://www.cnblogs.com/DswCnblog/p/5629165.html

https://www.cnblogs.com/langzou/p/5962033.html

http://shaoyuan1943.github.io/2016/03/26/explain-move-forward/

std::move()移动语义

std::move函数可以以非常简单的方式将左值引用转换为右值引用。

(左值、左值引用、右值、右值引用 参见:

http://www.cnblogs.com/SZxiaochun/p/8017475.html

https://blog.csdn.net/hyman_yx/article/details/52044632

通过std::move,可以避免不必要的拷贝操作。

std::move是为性能而生。

std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝。

智能指针

C++11后提供智能指针,shared_ptr、unique_ptr、weak_ptr(auto_ptr在C++11后弃用)。
auto_ptr不可作为容器元素,但unique_ptr,shared_ptr可以作为容器元素。。原因:stl的容器中有很多需要拷贝元素的操作,如排序、查找等。(unique_ptr)auto_ptr拷贝赋值时是所有权转移,而在容器中可能会产生临时对象拷贝赋值,临时对象获得所有权之后就析构了释放了对象。并且很难避免STL内部对容器中的元素实现赋值,这样便会使容器中多个元素被置位NULL。。
auto_ptr有拷贝语义,拷贝后源对象变得无效,这可能引发很严重的问题;而unique_ptr则无拷贝语义,但提供了移动语义,这样的错误不再可能发生,因为很明显必须使用std::move()进行转移。
auto_ptr不可指向动态数组,unique_ptr可以指向动态数组。因为unique_ptr有unique_ptr<T[]>重载版本,销毁动态对象时调用delete[]。

auto_ptr

auto_ptr是C++标准库中(<utility>)为了解决资源泄漏的问题提供的一个轻量级智能指针类模板(注意:这只是一种简单的智能指针)
auto_ptr的实现原理其实就是RAII,在构造的时候获取资源,在析构的时候释放资源,并进行相关指针操作的重载,使用起来就像普通的指针。

auto_ptr<A> a(new A());

auto_ptr没有考虑引用计数,因此一个对象只能由一个auto_ptr所拥有,在给其他auto_ptr赋值的时候,会转移这种所有权。
auto_ptr不能共享所有权,即不要让两个auto_ptr指向同一个对象。
auto_ptr不能指向数组,因为auto_ptr在析构的时候只是调用delete,而数组应该要调用delete[]。

shared_ptr

允许多个shared_ptr指向同一个对象。它通常使用make_shared()来构造。
shared_ptr有一个引用计数来记录有多少个其他shared_ptr指向相同的对象。
当shared_ptr对象被拷贝时,计数加1;当shared_ptr对象被赋予新值或销毁时,计数减1;
当一个share_ptr的引用计数为0时,它会自动释放所管理的对象(包括动态分配的内存)。

unique_ptr

unique_ptr“唯一”拥有其所指对象,同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有移动语义来实现)。
通过reset方法重新指定、通过release方法释放所有权、通过移动语义auto new_p = std::move(origin);转移所有权。

weak_ptr

weak_ptr是为了配合shared_ptr而引入的一种智能指针,因为它不具有普通指针的行为,没有重载operator和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。
使用weak_ptr的成员函数use_count()可以观测资源的引用计数.
另一个成员函数
expired()的功能等价于use_count()==0,但更快,表示被观测的资源(也就是shared_ptr的管理的资源)已经不复存在。
weak_ptr可以使用一个非常重要的成员函数
lock()*从被观测的shared_ptr获得一个可用的shared_ptr对象, 从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr。
!!!不要混合使用普通指针和智能指针

STL allocator

https://www.cnblogs.com/zhuwbox/p/3699977.html

一级配置器:直接调用malloc,free函数

二级配置器:如果申请空间小于128 Bytes,则调用一级配置器。否则从free list(8Bytes, 16Bytes, …, 128Bytes)中找。如果没有找到可用的free list,则调用refill()向内存池申请N(一般为20)个大小为8k的内存块,挂在对应free lists的指针上。

main函数执行前、后再执行的代码
全局对象的构造函数会在main 函数之前执行,
全局对象的析构函数会在main函数之后执行;
用atexit注册的函数也会在main之后执行。

struct 和类的区别

http://blog.sina.com.cn/s/blog_48f587a80100k630.html

本质区别:默认的访问控制不同。

1)默认的继承访问权限。struct是public的,class是private的。

2)struct作为数据结构的实现体,它默认的数据访问控制是public的;而class作为对象的实现体,它默认的成员变量访问控制是private的。

其他区别:“class”这个关键字还用于定义模板参数,就像“typename”。但关键字“struct”不用于定义模板参数。

C中的struct 和C++的 struct 的区别
c中的struct是没有权限设置的。

当然也没有面向对象的东西,如继承,构造函数,多态等。

C++内存管理

https://blog.csdn.net/caogenwangbaoqiang/article/details/79788368

包括内存分配,内存泄漏,内存回收。

10-07 10:43