C++面经总结之《Effective C++》(一)
发布日期:2021-06-30 19:47:51 浏览次数:2 分类:技术文章

本文共 2454 字,大约阅读时间需要 8 分钟。

在这里插入图片描述

面试感触

最厉害的面经,往往是如此的朴实无华(没别的意思,我的意思是,在座的面经,要成体系啊、)。

当时老师跟我说:你有多少水平,面试官是面的出来的。
所以刷那么多面经干嘛呢?还不如找套成体系的书或者课程,把自己真的会的东西拾掇拾掇来的实在。

我还是觉得,学习一项新技术,最难的不是学习本身,最难的是知道这个新技术。

学习能力摆在这里,目前有心仪的目标了。踏踏实实继续学吧。


条款

以下为我自己的读书感悟,如果各位有时间,建议自行搜索或购买这本书阅读,封面在开头有了、

1、将C++视为一个语言联邦

C标准C++模板C++STL

一千个哈姆雷特有一千个读者,大家自行体会吧、

我觉得,我得真的去接触一下模板编程了、

STL源码剖析也要再看一遍了,毕竟一年多了。


2、以编译器替换预处理器

首先第一点,就是你很可能在报错的时候找不到是什么情况。

这是我自己遇到的,但是我想不起来了。

碧如书中给的栗子:#define ASPECT_RATIO 1.653

报错的时候可能只给你个1.653, 你去哪里找这个1.653是个什么鬼、

我是想不起来当时的场景了,但是我知道当时使用了排除法排查了很久才找到。

解决之道:const double ASPECT_RATIO = 1.653

可能会有人说:define可以用来做宏定义函数,不会带来函数调用的开销。我不做评判,我只说我个人感觉,就是麻烦,而且不确定因素存在,最根本的原因就是我不了解它,而且也没那个欲望。


3、尽可能使用const

我就不吭声、

有多少人(还没参加工作的)知道写代码的时候应该尽可能使用const,有多少人真的在做?

好,我不多说,我自己也没在用这个。

之后会尽量记得把const添上的。

有个小细节需要注意的:

const void* a,这个时候,被const的是avoid * const a,这个时候,被const的是指针const void* const a,这个时候,a和指针都被const了

对于const的成员函数可以这样写:

const char& operator[](std::size_t position) const

4、确定对象被使用前已经被初始化

我们是否有写过这种代码:

int a,b,c;a = 0;b = 0;

成员变量有时候会初始化为0(或null),有时候不会。

记的不是很清楚,那时候没有写博客。我在做培训班的毕业项目的时候,曾经遇到过这么一个问题:数据包传输数据时不时的乱码。

当时就觉得很奇葩,你要传就传,不传就不传呗,传过去了你乱码是几个意思?

最后排查下来,问题出在了封装数据所用的char*没有在声明的时候被置空,出现了脏数据。后来给它初始化的时候手动置空,解决了问题。

反正呢,养成好习惯,在对象声明的时候给它一个身份。


5、了解C++空类默认构造函数

什么时候空类不再是一个空类呢?当C++处理过它之后。

如果你自己没声明,编译器会为它声明:一个拷贝构造函数、一个默认构造函数、一个析构函数、以及一个赋值操作符。

这个当时有问过,没想起来。


6、若不想使用编译器自动生成的函数,就明确拒绝

如果你不希望class支持某一特定机能,只要不声明对应函数就是了。

但这个策略对上面那几个不起作用的。

那怎么办?

其实吧,你可以将它们初始化为私有的,并且不去定义它们。


7、在多态虚基类中声明析构函数

这个就不提啦,会有内存泄漏。

8、别让异常逃离析构函数

这个上次也被问到了,但是没答上来。像这种知识点,看过就答得上来了。

C++并不禁止析构函数吐出异常,但它不鼓励你这样做。这是有理由的。

考虑以下代码:

class Widget{
public: ··· ~Widget(){
···}};void dosomething(){
std::vector
v;} //v在这里被自动销毁

当vector被销毁,它有责任带走所有的Widget。但是呢,如果在析构过程中,有个异常被抛出,那后面还没被析构的Widget怎么办?

好,继续。再被抛出异常,这也不是什么很奇怪的事情,有一就有二嘛。

在两个异常同时存在的情况下,程序要么强制结束,要么就是导致不明确行为。那就很尴尬了。


以下情况一直存在于我自己的代码中:将close函数置于析构函数中,并祈求不会出现问题(其实有时候我自己也不知道是不是真的被close了)。

只要调用成功,那就万事大吉、

但是如果该调用导致异常,那析构函数就会传播该异常,造成难以预料的问题。


解决办法有,之前看大佬的代码里有写,我也模仿过,但终究是不知道什么意思,放出来,现在知道了:

void DB::DB_close(){
db.close(); this->closed = true;}DB::~DB(){
if(!this->closed){
try(db,close();) catch(···){
//Python的异常抛出用的可六了,C++的倒是没有体验过 日志记录 } }|}

一般而言,将异常吞掉是一个坏主意,因为它压制了某些动作失败的重要信息。但是“不明确行为”也不是什么好事儿。

所以,就做一个接口,给客户端自行去调用关闭函数吧。

记住,析构函数一定不要吐出异常!!!

实在没办法,那咱也要像个硬汉,吞下去!!!


9、绝不在构造和析构过程中调用(自身)virtual函数

这个我看了很久。因为从第一眼,我就想到了线程池。

线程创建的时候,那不就得要传一个任务父类的run函数进去嘛?

后来看了半天,是不要在构造函数和析构过程中调用自身的虚函数,因为在这两个过程中,都会从最原始的那个父类开始往下执行,但是那时候它并不会去下降到子类的虚函数实现当中去。

或者可以这么说:在base class构造(销毁)期间,virtual函数不是virtual函数。

转载地址:https://lion-wu.blog.csdn.net/article/details/115013781 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:C++面经总结之《Effective C++》(二)
下一篇:二更!结合我的经验来看:Python到底该怎么学?拿下这些教程如有神助!

发表评论

最新留言

很好
[***.229.124.182]2024年04月18日 08时07分36秒