Effective Modern C++
文章平均质量分 90
娱乐界祖师爷
这个作者很懒,什么都没留下…
展开
-
条款42:考虑使用置入代替插入
然后,如果值已经存在,置入操作取消,创建的节点被销毁,意味着构造和析构时的开销被浪费了。在当前标准库的实现下,有些场景,就像预期的那样,置入执行性能优于插入,但是,有些场景反而插入更快。这种场景不容易描述,因为依赖于传递的实参的类型、使用的容器、置入或插入到容器中的位置、容器中类型的构造函数的异常安全性,和对于禁止重复值的容器(即。但是移动赋值需要一个源对象,所以这意味着一个临时对象要被创建,而置入优于插入的原因就是没有临时对象的创建和销毁,所以当通过赋值操作添加元素时,置入的优势消失殆尽。原创 2023-09-17 22:51:20 · 240 阅读 · 0 评论 -
条款12:使用override声明重写函数
C++使用override声明重写函数原创 2023-03-03 00:01:45 · 628 阅读 · 0 评论 -
条款41:针对可复制的形参,在移动成本低并且一定会被复制的前提下,考虑将其按值传递
(这样的句子就说明有一个术语来区分拷贝操作制作的副本,和移动操作制作的副本,是非常好的。对于特殊的场景,可拷贝且移动开销小的类型,传递给总是会拷贝他们的一个函数,并且切片也不需要考虑,这时,按值传递就提供了一种简单的实现方式,效率接近传递引用的函数,但是避免了传引用方案的缺点。结论是,使用通过赋值拷贝一个形参进行按值传递的函数的额外开销,取决于传递的类型,左值和右值的比例,这个类型是否需要动态分配内存,以及,如果需要分配内存的话,赋值操作符的具体实现,还有赋值目标占的内存至少要跟赋值源占的内存一样大。原创 2023-09-16 17:58:20 · 172 阅读 · 0 评论 -
条款40:对并发使用std::atomic,对特种内存使用valatile
由于x的型别是std::atomic,所以y的型别也会被推导为std::atomic.我之前说过,std::atomic型别对象最好的一点,是他们的所有操作都是原子的。出于相同的原因,复制赋值也被删除,这就是为什么从x到y的赋值通不过编译的原因(由于移动操作没有在std::atomic中显示声明,因此,根据条款17中描述的编译器生成特种函数的规则,std::atomic既不提供移动构造函数,也不提供移动赋值运算符)。此例在两方面值得注意。另一方面,vc的值则不一定是2,因为它的自增可能不会以原子方式发生。原创 2023-09-03 00:53:42 · 201 阅读 · 0 评论 -
条款39:考虑针对一次性事件通信使用以void为模板型别实参的期值
有时候,提供让一个任务通知另一个以异步方式运行的任务发生了特定的事件的能力,会是有用的,原因可能是第二个任务在事件发生之前无法推进。这事件也许是某个数据结构完成初始化,也许是某个计算阶段结束了,又也许是某个重要传感器取值被检测到了等。在此情况下,何为线程间通信的最佳方式?一种明显的途径是使用条件变量。若我们把检测条件的任务称为检测任务。把对条件做出反应的任务称为反应任务,则策略表示起来很简单:反应任务等待这条件变量,而检测任务则在事件发生时通知条件变量。原创 2023-08-13 15:57:22 · 123 阅读 · 0 评论 -
条款38:对变化多端的线程句柄析构函数行为保持关注
条款37解释过,可联结的线程对应着一个底层系统执行线程,未推迟任务(参见条款36)的期值和系统线程有类似关系。这么一来,std::thread型别对象和期值对象都可以视作系统线程的句柄。从这个视角来看,std::thread对象和期值对象的析构函数表现出如此不同的行为值得深思。正如条款37所提及的,针对可联结的std::thread型别对象实施析构会导致程序终止,因为另外两个显而易见的选择(隐式join和隐式detach)都被认为是更糟糕的选择。原创 2023-07-29 18:42:29 · 170 阅读 · 0 评论 -
条款37:使std::thread型别对象在所有路径皆不可联结
每个std::thread型别对象皆处于两种状态之一:可联结或不可联结。可联结的std::thread对应底层以异步方式已运行或可运行的线程。std::thread型别对象对应的底层线程若处于阻塞或等待调度,则它可联结。std::thread型别对象对应的底层线程如已运行至结束,则亦认为其可联结。不可联结的std::thread的意思如你所想:std::thread不处于以上可联结的状态。std::thread的可联结性之所以重要的原因之一是:如果可联结的线程对象的析构函数被调用,则程序的执行就终止了。原创 2023-07-25 00:49:18 · 75 阅读 · 0 评论 -
条款36:如果异步是必要的,则指定std::launch::async
当调用std::async来执行一个函数(或可调用对象)时,你基本是上都会想让函数以异步方式运行。但仅仅通过std::async来运行,你实际上要求的并非一定会达成异步运行的结果,你要求的仅仅是让该函数以符合std::async的启动策略来运行。标准策略有二,它们都是用限定作用域的枚举型别std::launch中的枚举量(关于限定作用域的枚举,参见条款10)来表示的。也许有点出人意料,std::aysnc的默认启动策略,也就是你如果不积极指定一个的话,它采用的并非以上两者中的一者。原创 2023-07-22 17:37:39 · 100 阅读 · 0 评论 -
条款35:优于选用基于任务而非基于线程的程序设计
如果你想以异步方式运行函数doAsyncWork,有两种基本选择。在这样的调用中,传递给std::async的函数对象(例如,doAsyncWork)被看作任务(task).基于任务的方法通常比基于线程实现的对应版本要好,即使从刚才我们看过的这么几行代码中,已经展示了一些原因。请看,doAsyncWork会产生一个返回值,我们有理由假定,调用doAsyncWork的代码会对该值感兴趣。在基于线程的调换用中,没有什么直截了当的办法能够获取该值;原创 2023-07-18 00:38:56 · 154 阅读 · 0 评论 -
条款34:优先选用lambda式,而非std::bind
std::bind是C++98中std::bind1st和std::bind2nd的后继特性,但是,作为一种非标准特性而言,std::bind在2005年就已经是标准库的组成部分了。正是在那时,标准委员会接受了名称TR1的文档,里面就包含了std::bind的规格(在TR1中,bind位于不同的名字空间,所以是std::tr1::bind而非std::bind,还有一些接口细节与现在有所不同)。原创 2023-07-16 20:54:28 · 197 阅读 · 0 评论 -
条款32:使用初始化捕获将对象移入闭包
有时,按值的捕获和按引用的捕获皆非你所欲。如果你想要把一个只移动对象(例如, std::unique_ptr或std::future型别的对象)放入闭包,C++11未提供任何办法做到此事。如果你有个对象,其复制操作开销昂贵,而移动操作成本低廉(例如,大部分标准容器库),而你又需要把该对象放入闭包。那么你肯定更愿意移动该对象,而非复制它。但是,C++11中也还是没有让你实现这一点的途径。但那只是C++11,C++14则有云泥之别。它为对象移动入闭包提供了直接支持。原创 2023-07-09 20:36:45 · 163 阅读 · 0 评论 -
条款31:避免默认捕获模式
C++11中有两种默认捕获模式:按引用或按值。按引用的默认捕获模式可能导致空悬引用,按值的默认捕获模式会忽悠你,好像可以对空悬引用免疫(其实并没有),你,让你认为你的闭包是独立的(事实上他们可能不是独立的)。这些就是本条款的纲领性内容了。但如果你本性上更偏向于工程师而不是领导,你就会不仅要一个骨架,还得有血有肉。所以我们就默认捕获模式的危害说起吧。按引用捕获会导致闭包包含指涉到局部变量的引用,或者指涉到定义lambda式的作用域内的形参的引用。原创 2023-07-07 00:37:51 · 179 阅读 · 0 评论 -
条款33:对auto&&型别的形参使用decltype,以std::forward之
泛型lambda式是C++14最振奋人心的特性之一——lambda可以在形参规格中使用auto.这个特性的实现十分直截了当:闭包类中的operator()采用模板实现。在本例中,lambda式对x实施的唯一动作就是将其转发给normalize,如果normalize区别对待左值和右值,则可说该lambda式撰写的是有问题的,因为,lambda总会传递左值(形参x)给normalize,即使传递给lambda式的实参是个右值。原创 2023-07-11 00:56:16 · 123 阅读 · 0 评论 -
条款30:熟悉完美转发的失败情形
会导致完美转发失败的实参种类有大括号初始化物、以值0或NULL表达的空指针、仅有声明的整型static const成员变量、模板或重载的函数名字,以及位域。原创 2023-06-15 00:58:00 · 616 阅读 · 0 评论 -
条款29:假定移动操作不存在、成本高、未使用
即使是那些支持快速移动操作的型别,一些看似万无一失的移动场景还是以复制副本告终,条款14解释过,标准库中一些容器操作提供了强异常安全保证,并且为了确保依赖于这样的保证,并且为了确保依赖于这样的保证的那些C++98的遗留代码在升级到C++11时不会破坏这样的保证,底层的复制操作只有在已知移动操作不会抛出异常的前提下才会使用移动操作将其替换。你可以直接查阅所使用的型别对移动的支持细节。举个例子,在标准的c++11库中,所有的容器都支持移动操作,但如果因此就断言所有的容器的移动都是成本低廉的,那就贻笑大方了。原创 2023-06-07 01:04:55 · 331 阅读 · 0 评论 -
条款27:熟悉依万能引用型别进行重载的替代方案
条款26说过,依万能引用型别进行重载会导致形形色色的问题,独立函数的成员函数(构造函数尤其问题严重)。不过,该条款也展示多少了这种重载可能有用的若干用例。这些用例的行为要是能按我们想要的那样运作就好了!本条款进行了一番探索,目的就在于获得期望的行为,方法是或者通过依万能引用型别进行重载的设计手法,或者通过限制能匹配的实参型别。原创 2023-06-01 00:59:22 · 425 阅读 · 0 评论 -
条款28:理解引用折叠
条款23曾经提及,实参在传递给函数模板时,推导出来的模板形参会将实参是左值还是右值的信息编码到结果型别中。但该条款未曾提及,这个编码操作只有在实参被用以初始化的形参为万能引用时才会发生。不过,有一个充分的理由来解释为什么当时不提这茬:万能引用时在条款24中才介绍。模板形参T的推导结果型别中,会把传给param的实参是左值还是右值的信息给编码进去。编码机制是直截了当的:如果传递的实参是个左值,T的推导结果就是个左值引用型别;原创 2023-06-04 23:00:23 · 647 阅读 · 0 评论 -
条款26:避免依万能引用型别进行重载
避免依万能引用型别进行重载原创 2023-04-13 01:12:31 · 280 阅读 · 2 评论 -
条款25:对右值引用使用std::move,对通用引用使用std::forward
对右值引用使用std::move,对通用引用使用std::forward原创 2023-03-26 23:57:30 · 396 阅读 · 0 评论 -
条款24:区分通用引用与右值引用
C++区分通用引用与右值引用原创 2023-03-26 18:49:32 · 331 阅读 · 0 评论 -
条款23:理解std::move和std::forward
理解C++ std::move和std::forward原创 2023-03-19 23:28:29 · 247 阅读 · 0 评论 -
条款22:当使用Pimpl惯用法,请在实现文件中定义特殊成员函数
当使用Pimpl惯用法,请在实现文件中定义特殊成员函数原创 2023-03-19 17:29:02 · 339 阅读 · 0 评论 -
条款21:优先考虑使用std::make_unique和std::make_shared,而非直接使用new
优先考虑使用std::make_unique和std::make_shared,而非直接使用new原创 2023-03-19 00:14:22 · 559 阅读 · 0 评论 -
条款20:当std::shared_ptr可能悬空时使用std::weak_ptr
当std::shared_ptr可能悬空时使用std::weak_ptr原创 2023-03-18 21:31:03 · 490 阅读 · 0 评论 -
条款19:对于共享资源使用std::shared_ptr
C++对于共享资源使用std::shared_ptr原创 2023-03-15 22:52:04 · 447 阅读 · 0 评论 -
条款18:对于独占资源使用std::unique_ptr
对于独占资源使用std::unique_ptr原创 2023-03-15 00:09:13 · 209 阅读 · 0 评论 -
条款17:理解特殊成员函数的生成
理解C++特殊成员函数的生成规则原创 2023-03-12 23:06:46 · 148 阅读 · 0 评论 -
条款16:让const成员函数线程安全
C++ const成员函数应该支持线程安全原创 2023-03-12 12:47:26 · 218 阅读 · 0 评论 -
条款15:尽可能的使用constexpr
C++尽可能的使用constexpr原创 2023-03-12 00:35:51 · 342 阅读 · 0 评论 -
条款14:如果函数不抛出异常请使用noexcept
C++11如果函数不抛出异常请使用noexcept原创 2023-03-11 22:39:17 · 331 阅读 · 0 评论 -
条款13:优先考虑const_iterator而非iterator
优先考虑const_iterator而非iterator原创 2023-03-04 01:19:12 · 446 阅读 · 0 评论 -
条款11:优先考虑使用deleted函数而非使用未定义的私有声明
优先考虑使用deleted函数而非使用未定义的私有声明原创 2023-03-02 23:20:31 · 130 阅读 · 0 评论 -
条款10:优先考虑限域enum而非未限域enum
优先使用enum class 而非 enum原创 2023-02-28 23:47:08 · 194 阅读 · 0 评论 -
条款9:优先考虑别名声明而非typedefs
C++优先考虑使用别名声明(using)而不是typedef原创 2023-02-28 00:33:53 · 127 阅读 · 0 评论 -
条款8:优先考虑nullptr而非0和NULL
现代C++优先使用nullptr,而不是0和NULL原创 2023-02-26 18:09:26 · 466 阅读 · 0 评论 -
条款7:区别使用()和{}创建对象
C++使用{}与使用()初始化的区别原创 2023-02-26 16:31:43 · 521 阅读 · 0 评论 -
条款6:当auto推导的型别不符合要求时,使用带显示型别的初始化物习惯用法
这种做法给std::vector的operator[]带来了一个问题,因为按理说std::vector的operator[]应该返回一个T&,然而C++却禁止bit的引用,既然不能返回一个bool&,std::vector的operator[]转而返回一个表现的像bool&的对象, 而这个把戏若要成功,std::vector::reference型别的对象就要在所有能用bool&的地方保证它们也能用。但是有的情况下,你想往东,auto型别推导的结果偏偏往西。原创 2023-02-25 20:37:46 · 871 阅读 · 0 评论 -
条款5:优先选用auto,而非显示型别声明
而使用std::function声明的、存储着一个闭包的变量是std::function的一个实例,所以不管给定的签名如何,它都占有固定尺寸的内存,而这个尺寸对于其存储的闭包而言并不一定能够用,如果这样的话,std::function的构造函数就会分配堆上的内存来存储该闭包。在持有闭包的这场发生在auto和std::function之间的较量中,auto可谓大获全胜(如果再来一场较量,在auto和std::function之间比较持有std::bind的调用结果,则比分是一样的)。原创 2023-02-12 00:04:51 · 394 阅读 · 0 评论 -
条款3:理解decltype
C++中decltype的典型使用原创 2023-02-04 23:51:59 · 196 阅读 · 0 评论 -
条款2:理解auto型别推导
C++中auto使用的注意事项原创 2023-01-25 18:02:09 · 652 阅读 · 0 评论