1.自我介绍
2.说一下三种智能指针和它们的特点
unique_ptr:同一时间内只有一个智能指针可以指向该对象
shared_ptr:多个智能指针可以指向相同对象,强引用
weak_ptr:配合 shared_ptr 使用,防止两个 shared_ptr 互相引⽤导致资源永远不释放(引用计数永不为0)
3.shared_ptr是通过什么方式实现的
引用计数。引用时增加计数,销毁时减少计数,计数为0时释放资源。
4.const int * 和int * const
const int * 指向整型常量的指针,它指向的值不能更改
int * const 指向整型的常量指针,它不能再指向别的变量
5.面向对象的三大特性
封装、继承、多态(多态突然想不起来,面试官提醒后想起来了)
6.析构函数为什么一般写成虚函数
加入一个基类的指针指向一个派生类的对象,如果析构函数不是虚函数,销毁时会调用基类的析构函数,派生类的自身内容就不会被析构,会导致内存泄漏。如果析构函数是虚函数,则会根据指针所指对象的虚函数表执行派生类的析构函数,再执行基类的析构函数。
7.vector的扩容机制
添加元素时,会判断当前是否还有剩余空间,如果没有则会进行扩容,将内存拷贝到新申请的内存空间上,并且释放原先的内存。
8.有了解过vector扩容会扩多少吗
没有(面试官说是扩到原来的两倍,不过面试结束后我去查说是跟环境有关,不一定是两倍)
9.假如已经创建了一个vector,现在有两种情况,第一种是确定vector中有10000个元素,第二种是确定vector中最多有10000个元素,为了绕开自动扩容机制,应该怎样处理(问题经过简单修改,最开始怎么问的我忘了,我最开始答的使用push_back和emplace_back)
第一种情况使用resize(),二种情况使用reserve()
10.resize()和reserve()的区别
resize()改变当前容器内元素的数量
reserve()改变当前容器的最大容量
11.假设最开始vector中有两个元素,resize(10000)和reserve(10000)之后调用size()返回值是多少
10000
2
12.刚才你提到了push_back()和emplace_back(),区别是什么
push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);而 emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程。
13.讲讲最常用的单例模式是怎么实现的
①类中包含⼀个静态成员指针,该指针指向该类的⼀个对象,提供⼀个公有的静态成员⽅法,返回该对象指针;
②为了使得对象唯⼀,构造函数和拷贝构造函数设为私有。
一道与面试题 08.11. 硬币类似的题
硬币。给定数量不限的硬币,所有币值为一个数组,编写代码计算n分有几种表示法。
int count(int amount,vector<int>&coins){ int coins_num=coins.size(); vector<vector<int>>dp(coins_num+1,vector<int>(amount+1,0)); int l=coins.size(); for(int i=0;i<l;++i){ dp[i][0]=1; } for(int j = 0;j<coins_num;j++){ for(int i=1;i<=amount;i++){ for(int k=0;k<=i/coins[j];k++){ dp[j+1][i]+=dp[j][i-k*coins[j]]; } } } return dp[coins_num][amount]; }
面试官看完之后说我这个逻辑上没问题,递推式也没问题,但时空复杂度都比较高,跟我仔细地分析了代码可以优化的地方
int count(int amount,vector<int>&coins){ int coins_num=coins.size(); vector<int>dp(amount+1,0); int l=coins.size(); dp[0]=1; for(int j = 0;j<coins_num;j++){ for(int i = coins[j];i <= amount;i++){ dp[i]+=dp[i-coins[j]]; } } return dp[amount]; }
总体来说面试官很好,没有给太大压力,整体氛围很轻松。
最后也给了我建议(动态规划是我的软肋,最好要克服)
#23届找工作求助阵地#