举个栗子2
更多笔记关注wx公众号:cpp读书笔记
展开
-
Effective ModernC++条款42:考虑使用置入代替插入
然后,如果值已经存在,置入操作取消,创建的节点被销毁,意味着构造和析构时的开销被浪费了。在当前标准库的实现下,有些场景,就像预期的那样,置入执行性能优于插入,但是,有些场景反而插入更快。这种场景不容易描述,因为依赖于传递的实参的类型、使用的容器、置入或插入到容器中的位置、容器中类型的构造函数的异常安全性,和对于禁止重复值的容器(即。但是移动赋值需要一个源对象,所以这意味着一个临时对象要被创建,而置入优于插入的原因就是没有临时对象的创建和销毁,所以当通过赋值操作添加元素时,置入的优势消失殆尽。原创 2024-05-24 09:19:40 · 973 阅读 · 0 评论 -
Effective Modern C++ 条款41:对于移动成本低且总是被拷贝的可拷贝形参,考虑按值传递
(这样的句子就说明有一个术语来区分拷贝操作制作的副本,和移动操作制作的副本,是非常好的。对于特殊的场景,可拷贝且移动开销小的类型,传递给总是会拷贝他们的一个函数,并且切片也不需要考虑,这时,按值传递就提供了一种简单的实现方式,效率接近传递引用的函数,但是避免了传引用方案的缺点。结论是,使用通过赋值拷贝一个形参进行按值传递的函数的额外开销,取决于传递的类型,左值和右值的比例,这个类型是否需要动态分配内存,以及,如果需要分配内存的话,赋值操作符的具体实现,还有赋值目标占的内存至少要跟赋值源占的内存一样大。原创 2024-05-24 09:18:41 · 1587 阅读 · 0 评论 -
Effective Modern C++ 条款40:对于并发使用std::atomic,对于特殊内存使用volatile
但是它们通常做出一些没有数据竞争的程序中才有效的优化,这些优化在存在数据竞争的程序中会造成异常和不可预测的行为。但是在编译器拿到看起来合理的代码,执行了模板实例化,内联和一系列重排序优化之后,结果会出现冗余访问和无用存储,所以编译器需要摆脱这样的情况并不少见。)这意味对我们的代码,对象被构建,在其上的操作表现得像操作是在互斥锁保护的关键区内,但是通常这些操作是使用特定的机器指令实现,这比锁的实现更高效。那些不那么相同,但是如果我们暂时忽略它,只关注编译器执行的操作,则概念上可以说,编译器看到这个,原创 2024-05-23 10:22:40 · 839 阅读 · 0 评论 -
Effective Modern C++ 条款39:对于一次性事件通信考虑使用void的futures
互斥锁被用于保护共享数据的访问,但是可能检测任务和反应任务可能不会同时访问共享数据,比如说,检测任务会初始化一个全局数据结构,然后给反应任务用,如果检测任务在初始化之后不会再访问这个数据结构,而在检测任务表明数据结构准备完了之前反应任务不会访问这个数据结构,这两个任务在程序逻辑下互不干扰,也就没有必要使用互斥锁。不好的一点是反应任务中轮询的开销。这样,反应线程占用了可能能给另一个任务使用的硬件线程,每次启动或者完成它的时间片都增加了上下文切换的开销,并且保持核心一直在运行状态,否则的话本来可以停下来省电。原创 2024-05-23 10:21:52 · 932 阅读 · 0 评论 -
Effective Modern C++ 条款38:关注不同线程句柄的析构行为
最后,决定先不改变,所以C++11和C++14中这里的行为是一致的。满足上面条件的任意一条(比如由于程序逻辑造成的不满足),你就可以确定析构函数不会执行“异常”行为。因为与被调用者关联的对象和与调用者关联的对象都不适合存储这个结果,所以必须存储在两者之外的位置。阻塞了它们的析构函数”。我们真正要处理的是一个简单的“正常”行为以及一个单独的例外。的数据成员(当然,还做了另一件事,就是递减了共享状态中的引用计数,这个共享状态是由引用它的。创建的共享状态才有资格执行“异常”行为,但是有其他创建共享状态的方式。原创 2024-05-22 08:17:14 · 1068 阅读 · 0 评论 -
Effective ModernC++ 条款37:使std::thread在所有路径最后都不可结合
如果同时进行调用,那肯定是有竞争的,但是不在析构函数中,是在客户端代码中试图同时在一个对象上调用两个成员函数(析构函数和其他函数)。在这个类中,这个顺序没什么特别之处,但是通常,可能一个数据成员的初始化依赖于另一个,因为。的可结合性如此重要的原因之一就是当可结合的线程的析构函数被调用,程序执行会终止。比如,假定有一个函数。可以视作状态保存的对象,保存的状态可能也包括可调用对象,有没有具体的线程承载就是有没有连接),然后选择析构执行的动作,这比反过来更合理),但是成员初始化列表设计的匹配成员声明的顺序。原创 2024-05-22 08:14:52 · 950 阅读 · 0 评论 -
EffectiveModernC++ 条款36:如果有异步的必要请指定std::launch::async
那些是使机器资源超额或者线程耗尽的条件,此时任务推迟执行才最有可能发生。毕竟,如果硬件没有资源耗尽,没有理由不安排任务并发执行。的默认启动策略——你不显式指定一个策略时它使用的那个——不是上面中任意一个。相反,是求或在一起的。作为启动策略的工具,拥有它会非常方便,而且编写起来很容易也使它看起来很棒。和标准库的线程管理组件承担线程创建和销毁的责任,避免资源超额,以及平衡负载。执行函数时(或者其他可调用对象),你通常希望异步执行函数。的循环使用超时机制,因为在一个延时的任务(参见[Item35])上调用。原创 2024-05-20 21:39:34 · 1046 阅读 · 0 评论 -
Effective ModernC++ 条款35:优先考虑基于任务的编程而非基于线程的编程
避免资源超额很困难,因为软件线程之于硬件线程的最佳比例取决于软件线程的执行频率,那是动态改变的,比如一个程序从IO密集型变成计算密集型,执行频率是会改变的。此外,硬件线程的数量和CPU缓存的细节(比如缓存多大,相应速度多少)取决于机器的体系结构,即使经过调校,在某一种机器平台避免了资源超额(而仍然保持硬件的繁忙状态),换一个其他类型的机器这个调校并不能提供较好效果的保证。遇到负载不均衡问题时,对机器内发生的事情,运行时调度程序比你有更全面的了解,因为它管理的是所有执行过程,而不仅仅个别开发者运行的代码。原创 2024-05-20 21:38:18 · 825 阅读 · 0 评论 -
Effective Modern C++ 条款34:考虑lambda而非std::bind
无论如何,这样的理解都是值得的,因为你永远不知道何时会在阅读或维护的代码库中遇到。这是可以理解的,但是在这种情况下,改变是更好的,因为在C++11中,在C++14中,通常可以省略标准运算符模板的模板类型实参,因此无需在此处提供。进一步假设,在程序的某个时刻,我们已经确定需要设置一个小时后响30秒的警报器。(答案是传递给bind对象的所有实参都是通过引用传递的,因为此类对象的函数调用运算符使用完美转发。)等简化在C++14中的代码,其中标准后缀基于C++11对用户自定义常量的支持。的调用是通过一个函数指针。原创 2024-05-18 08:31:00 · 781 阅读 · 0 评论 -
Effective Modern C++ 条款33:对auto&&形参使用decltype以std::forward它们
Item28解释过如果一个左值实参被传给通用引用的形参,那么形参类型会变成左值引用。传递的是右值,形参就会变成右值引用。时,惯例决定了类型实参是左值引用时来表明要传进左值,类型实参是非引用就表明要传进右值。是非传统的,不过它产生的实例化结果与传统类型相同。去实例化产生的结果,它们完全相同。一般来说,当你在使用完美转发时,你是在一个接受类型参数为。这个特性的实现是非常直截了当的:即在闭包类中的。的类型来确定传递进来的实参是一个左值还是右值,如果传递的是一个右值,指定为右值引用,这会发生什么。原创 2024-05-18 08:30:11 · 684 阅读 · 0 评论 -
Effective ModernC++ 条款32:使用初始化捕获来移动对象到闭包中
如果你要复制的对象复制开销非常高,但移动的成本却不高(例如标准库中的大多数容器),并且你希望的是宁愿移动该对象到闭包而不是复制它。表达式要多,但这并不难改变这样一个事实,即如果你希望使用一个C++11的类来支持其数据成员的移动初始化,那么你唯一要做的就是在键盘上多花点时间。这清楚地表明了,这个C++14的捕获概念是从C++11发展出来的的,在C++11中,无法捕获表达式的结果。这种移动构造是模仿移动捕获的关键,因为将右值移动到bind对象是我们解决无法将右值移动到C++11闭包中的方法。原创 2024-05-17 09:14:50 · 598 阅读 · 0 评论 -
Effective ModernC++ 条款31:避免使用默认捕获模式
但默认按引用捕获模式可能会带来悬空引用的问题,而默认按值捕获模式可能会诱骗你让你以为能解决悬空引用的问题(实际上并没有),还会让你以为你的闭包是独立的(事实上也不是独立的)。在这种情况下,你可能会争论说,没有悬空引用的危险,就不需要避免使用默认的引用捕获模式。使用默认的按值捕获还有另外的一个缺点,它们预示了相关的闭包是独立的并且不受外部数据变化的影响。,这和默认的按值捕获表示的含义有着直接的矛盾。捕获并没有默认的捕获模式,因此在C++14中,本条款的建议——避免使用默认捕获模式——仍然是成立的。原创 2024-05-17 09:13:44 · 943 阅读 · 0 评论 -
Effective Modern C++ 条款30:熟悉完美转发失败的情况
在大多数情况下,完美转发工作的很好。你基本不用考虑其他问题。但是当其不工作时——当看起来合理的代码无法编译,或者更糟的是,虽能编译但无法按照预期运行时——了解完美转发的缺陷就很重要了。同样重要的是如何解决它们。在大多数情况下,都很简单。当模板类型推导失败或者推导出错误类型,完美转发会失败。导致完美转发失败的实参种类有花括号初始化,作为空指针的0或者NULL,仅有声明的整型数据成员,模板和重载函数的名字,位域。原创 2024-05-16 09:56:24 · 1208 阅读 · 0 评论 -
EffectiveModern C++ 条款29:假定移动操作不存在,成本高,未被使用
为了升级到C++11,C++98的很多标准库做了大修改,为很多类型提供了移动的能力,这些类型的移动实现比复制操作更快,并且对库的组件实现修改以利用移动操作。的确,C++11倾向于为缺少移动操作的类生成它们,但是只有在没有声明复制操作,移动操作,或析构函数的类中才会生成移动操作(参考Item17)。Item14解释了原因,标准库中的某些容器操作提供了强大的异常安全保证,确保依赖那些保证的C++98的代码在升级到C++11且仅当移动操作不会抛出异常,从而可能替换操作时,不会不可运行。但是传说总有些夸大成分。原创 2024-05-16 09:55:23 · 877 阅读 · 0 评论 -
Effective Modern C++ 条款28:理解引用折叠
存在两种类型的引用(左值和右值),所以有四种可能的引用组合(左值的左值,左值的右值,右值的右值,右值的左值)。如果一个上下文中允许引用的引用存在(比如,模板的实例化),引用根据规则。通用引用的概念是有用的,因为它使你不必一定意识到引用折叠的存在,从直觉上推导左值和右值的不同类型,在凭直觉把推导的类型代入到它们出现的上下文中之后应用引用折叠规则。和通用引用之前,必须明确在C++中引用的引用是非法的。会产生对左值引用的右值引用,然后引用折叠规则告诉我们结果就是左值引用。第一,也是最常见的就是模板实例化。原创 2024-05-15 07:40:12 · 774 阅读 · 0 评论 -
Effective Modern C++ 条款27:熟悉通用引用重载的替代方法
更多C++学习笔记,关注 wx公众号:cpp读书笔记中说明了对使用通用引用形参的函数,无论是独立函数还是成员函数(尤其是构造函数),进行重载都会导致一系列问题。但是也提供了一些示例,如果能够按照我们期望的方式运行,重载可能也是有用的。这个条款探讨了几种,通过避免在通用引用上重载的设计,或者通过限制通用引用可以匹配的参数类型,来实现所期望行为的方法。讨论基于中的示例,如果你还没有阅读那个条款,请先阅读那个条款再继续。原创 2024-05-15 07:39:13 · 717 阅读 · 0 评论 -
Effective Modern C++ 条款26:避免在通用引用上重载
中说明,在适当的条件下,C++会生成拷贝和移动构造函数,即使类包含了模板化的构造函数,模板函数能实例化产生与拷贝和移动构造函数一样的签名,也在合适的条件范围内。如同注释表示的,派生类的拷贝和移动构造函数没有调用基类的拷贝和移动构造函数,而是调用了基类的完美转发构造函数!根据正常的重载解决规则,精确匹配优先于类型提升的匹配,所以被调用的是通用引用的重载。确实我们是这样想的,但是编译器严格遵循C++的规则,这里的相关规则就是控制对重载函数调用的解析规则。使用通用引用的函数在C++中是最贪婪的函数。原创 2024-05-14 08:57:20 · 639 阅读 · 0 评论 -
Effective Modern C++ 条款25:对右值引用使用std::move,对通用引用使用std::forward
对标准中教条的(也可以说是有毒的)絮叨做些解释,这个特定的好事就是说,编译器可能会在按值返回的函数中消除对局部对象的拷贝(或者移动),如果满足(1)局部对象与函数返回值的类型相同;增加的开销根据实现不同而不同,这些开销是否值得担心也跟应用和库的不同而有所不同,但是事实上,将通用引用模板替换成对左值引用和右值引用的一对函数重载在某些情况下会导致运行时的开销。一些人将RVO的应用区分为命名的和未命名的(即临时的)局部对象,限制了RVO术语应用到未命名对象上,并把对命名对象的应用称为。而是设计的可扩展性差。原创 2024-05-14 08:56:53 · 731 阅读 · 0 评论 -
EffectiveModern C++ 条款24:区分通用引用与右值引用
如果初始值是一个右值,那么通用引用就会是对应的右值引用,如果初始值是一个左值,那么通用引用就会是一个左值引用。,它们依赖于右值引用和通用引用的区别。就像牛顿的力学定律(本质上不正确),比起爱因斯坦的广义相对论(这是真相)而言,往往更简单,更易用。”),并且,当你在和你的合作者交流时,它会帮助你避免歧义(“在这里我在用一个通用引用,而非右值引用”)。它们的二重性使它们既可以绑定到右值上(就像右值引用),也可以绑定到左值上(就像左值引用)。”的另一种意思是,它既可以是右值引用,也可以是左值引用。原创 2024-05-13 09:07:18 · 788 阅读 · 0 评论 -
Effective Modern C++ 条款23:理解std::move和std::forward
前者是典型地为了移动操作,而后者只是传递(亦为转发)一个对象到另外一个函数,保留它原有的左值属性或右值属性。的吸引力在于它的便利性:减少了出错的可能性,增加了代码的清晰程度。是移动操作的候选者。接受一个对象的引用(准确的说,一个通用引用(universal reference),见。的,因为我们可以到处直接写转换代码,但是我希望我们能同意:这将相当的,嗯,让人恶心。返回的真的是右值引用,这很重要,因为函数返回的右值引用是右值。,你能确保的唯一一件事就是将它应用到一个对象上,你能够得到一个右值。原创 2024-05-13 09:06:50 · 675 阅读 · 0 评论 -
Effective Modern C++ 条款22:当使用Pimpl惯用法,请在实现文件中定义特殊成员函数
凭借这样一种技巧,你可以将类数据成员替换成一个指向包含具体实现的类(或结构体)的指针,并将放在主类(primary class)的数据成员们移动到实现类(implementation class)去,而这些数据成员的访问将通过指针间接访问。而言,删除器的类型不是该智能指针的一部分,这让它会生成更大的运行时数据结构和稍微慢点的代码,但是当编译器生成的特殊成员函数被使用的时候,指向的对象不必是一个完整类型。这样的做法会导致同样的错误,和之前的声明一个不带析构函数的类的错误一样,并且是因为同样的原因。原创 2024-05-11 09:18:19 · 888 阅读 · 0 评论 -
Effective Modern C++ 条款21:优先考虑使用std::make_unique和std::make_shared,而非直接使用new
源代码中的重复增加了编译的时间,会导致目标代码冗余,并且通常会让代码库使用更加困难。但是,因为控制块和对象被放在同一块分配的内存块中,直到控制块的内存也被销毁,对象占用的内存才被释放。这种优化减少了程序的静态大小,因为代码只包含一个内存分配调用,并且它提高了可执行代码的速度,因为内存只分配一次。这些函数的存在意味着对这些类型的对象的全局内存分配和释放是不合常规的。中的两个:接收任意的多参数集合,完美转发到构造函数去动态分配一个对象,然后返回这个指向这个对象的指针。函数中,完美转发使用小括号,而不是花括号。原创 2024-05-11 09:17:50 · 620 阅读 · 0 评论 -
Effective Modern C++ 条款20:当std::shared_ptr可能悬空时使用std::weak_ptr
此模式的主要组件是subjects(状态可能会更改的对象)和observers(状态发生更改时要通知的对象)。调用者应该接收缓存对象的智能指针,调用者也应该确定这些对象的生命周期,但是缓存本身也需要一个指针指向它所缓存的对象。缓存对象的指针需要知道它是否已经悬空,因为当工厂客户端使用完工厂产生的对象后,对象将被销毁,关联的缓存条目会悬空。当然,不是所有的使用指针的数据结构都是严格分层的,所以当发生这种情况时,比如上面所述缓存和观察者列表的实现之类的,知道。)的但是不参与资源所有权共享的指针是很方便的。原创 2024-05-10 09:05:25 · 709 阅读 · 0 评论 -
EffectiveModern C++ 条款19:对于共享资源使用std::shared_ptr
执行需要原子引用计数修改的操作需要承担一两个原子操作开销,这些操作通常都会一一映射到机器指令上,所以即使对比非原子指令来说,原子指令开销较大,但是它们仍然只是单个指令上的。对象的指针,它是未定义行为的Game, Set, and Match(译注:一部关于网球的电影,但是译者没看过。的构造函数一个原始指针,它会为指向的对象创建一个控制块(因此有个引用计数值)。作为这些轻微开销的交换,你得到了动态分配的资源的生命周期自动管理的好处。就垃圾回收来说,客户端不需要关心指向对象的生命周期,而对象的析构是确定性的。原创 2024-05-10 09:04:46 · 954 阅读 · 0 评论 -
Effective Modern C++ 条款18:对于独占资源使用std::unique_ptr
一种隐藏实际实现而减弱编译依赖性的设计思想,《Effective C++》条款31对此有过叙述)的一种机制,它更为流行。对于函数对象形式的删除器来说,变化的大小取决于函数对象中存储的状态多少,无状态函数(stateless function)对象(比如不捕获变量的。返回的对象的自定义的删除器。所有的自定义的删除行为接受要销毁对象的原始指针,然后执行所有必要行为实现销毁操作。发生这种情况时,这个对象的。有用的唯一情况是你使用类似C的API返回一个指向堆数组的原始指针,而你想接管这个数组的所有权。原创 2024-05-09 09:30:48 · 1260 阅读 · 0 评论 -
Effective ModernC++条款17:理解特殊成员函数的生成
它来源于长期的观察,即用户接管拷贝操作的需求几乎都是因为该类会做其他资源的管理,这也几乎意味着(1)无论哪种资源管理如果在一个拷贝操作内完成,也应该在另一个拷贝操作内完成(2)类的析构函数也需要参与资源的管理(通常是释放)。)(译注:禁用的是自动生成的拷贝操作,对于用户声明的拷贝操作不受影响)毕竟,如果逐成员移动对该类来说不合适,也没有理由指望逐成员拷贝操作是合适的。规则背后的解释依然有效,再加上对声明拷贝操作阻止移动操作隐式生成的观察,使得C++11不会为那些有用户定义的析构函数的类生成移动操作。原创 2024-05-09 09:28:54 · 892 阅读 · 0 评论 -
Effective Modern C++ 条款16:让const成员函数线程安全
在这个类中,使用一个函数来计算多项式的根是很有用的,也就是多项式的值为零的时候(译者注:通常也被叫做零点,即使得多项式值为零的那些取值)。计算多项式的根是很复杂的,因此如果不需要的话,我们就不做。在没有同步的情况下,让多个线程执行读操作是安全的。声明在C++11中与在C++98中一样正确(检索多项式的根并不会更改多项式的值),因此需要纠正的是线程安全的缺乏。这就意味着在没有同步的情况下,这些代码会有不同的线程读写相同的内存,这就是数据竞争(的经典使用样例,这也是为什么它是数据成员声明的一部分。原创 2024-05-08 08:58:58 · 808 阅读 · 0 评论 -
Effective Modern C++ 条款15:尽可能的使用constexpr
(技术上来讲,它们的值在翻译期(translation)决议,所谓翻译不仅仅包含是编译(compilation)也包含链接(linking),除非你准备写C++的编译器和链接器,否则这些对你不会造成影响,所以你编程时无需担心,把这些。)它也意味着以前相对严格的编译期完成的工作和运行时完成的工作的界限变得模糊,一些传统上在运行时的计算过程能并入编译时。如果你想编译器保证一个变量有一个值,这个值可以放到那些需要编译期常量(compile-time constants)的上下文的地方,你需要的工具是。原创 2024-05-08 08:57:43 · 754 阅读 · 0 评论 -
Effective Modern C++ 条款14:如果函数不抛出异常请使用noexcept
如果一个简单的函数实现可能引发异常(比如调用一个可能抛异常的函数),而你为了讨好调用者隐藏了这个(比如捕获所有异常,然后替换为状态码或者特殊返回值),这不仅会使你的函数实现变得复杂,还会让调用点的代码变得复杂。)是喜怒无常的野兽。如果一个对象的析构函数可能被标准库使用(比如在容器内或者被传给一个算法),析构函数又可能抛异常,那么程序的行为是未定义的。,因为它们可能抛出那种“让它们过吧”的异常(译注:也就是说在当前这个函数内不处理异常,但是又不立即终止程序,而是让调用这个函数的函数处理异常。原创 2024-05-07 09:58:55 · 885 阅读 · 0 评论 -
Effective Modern C++ 条款13:优先考虑const_iterator而非iterator
支持不足(译注:C++14支持但是C++11的时候还没)的情况是:当你想写最大程度通用的库,并且这些库代码为一些容器和类似容器的数据结构提供。如果你使用C++11,并且想写一个最大程度通用的代码,而你使用的STL没有提供缺失的非成员函数。首先不容易创建它们,其次就算你有了它,它的使用也是受限的。提到的别名声明,因为这段代码在演示C++98做法,别名声明是C++11加入的特性)上面的说法对C++11和C++98都是正确的,但是在C++98中,标准库对。(它不是C++98的限制,也不是C++11的限制,只是。原创 2024-05-07 09:58:34 · 801 阅读 · 0 评论 -
Effective Modern C++ 条款12:使用override声明重写函数
比如,下面的代码是完全合法的,咋一看,还很有道理,但是它没有任何虚函数重写——没有一个派生类函数联系到基类函数。后面我还会提到引用限定符修饰成员函数,但是现在,只需要记住如果基类的虚函数有引用限定符,派生类的重写就必须具有相同的引用限定符。,你可以只改变基类函数签名,重编译系统,再看看你造成了多大的问题(即,多少派生类不能通过编译),然后决定是否值得如此麻烦更改函数签名。,你只能寄希望于完善的单元测试,因为,正如我们所见,派生类虚函数本想重写基类,但是没有,编译器也没有探测并发出诊断信息。原创 2024-05-05 09:17:54 · 892 阅读 · 0 评论 -
Effective Modern C++ 条款11:优先考虑使用deleted函数而非使用未定义的私有声明
本节主要致力于讨论C++98中那些被C++11所取代的最佳实践,而且在C++98中,你想要禁止使用的成员函数,几乎总是拷贝构造函数或者赋值运算符,或者两者都是。如果你写的代码要被其他人使用,你不想让他们调用某个特殊的函数,你通常不会声明这个函数。函数不能被使用,但它们还是存在于你的程序中。(经典的C++98惯例)来禁止这些函数模板实例化,但是不能这样做,因为不能给特化的成员模板函数指定一个不同于主函数模板的访问级别。这是较之C++98行为的一个改进,C++98中不正确的使用这些函数在链接时才被诊断出来。原创 2024-05-05 09:16:34 · 731 阅读 · 0 评论 -
Effective Modern C++ 条款10:优先考虑限域enum而非未限域enum
要写更多的代码,但同时它也避免命名空间污染,防止不经意间使用隐式转换。大多数情况下,你应该会觉得多敲几个(几行)字符作为避免使用未限域枚举这种老得和2400波特率猫同时代技术的代价是值得的。在一些情况下,编译器将会优化速度,舍弃大小,这种情况下它可能不会选择最小的底层类型,而是选择对优化大小有帮助的类型。那么可能整个系统都得重新编译,即使只有一个子系统——或者只有一个函数——使用了新添加的枚举名。还有第二个吸引人的优点:在它的作用域中,枚举名是强类型。的定义发生改变,包含这些声明的头文件也不需要重新编译。原创 2024-05-03 09:24:47 · 800 阅读 · 0 评论 -
Effective Modern C++ 条款9:优先考虑别名声明而非typedef
关于为什么这么实现是有历史原因的,但是我们跳过它(我认为太无聊了),因为标准委员会没有及时认识到别名声明是更好的选择,所以直到C++14它们才提供了使用别名声明的版本。(如果你没有用过模板元编程,太遗憾了,因为如果你真的想成为一个高效C++程序员,你需要至少熟悉C++在这方面的基本知识。在你的项目使用它们之前,你最好看看它们的详细说明书。和别名声明做的都是完全一样的事情,我们有理由想知道会不会出于一些技术上的原因两者有一个更好。是C++98的东西。,也不全是类型转换的工具,也包含一些可预测接口的工具。原创 2024-05-03 09:23:21 · 56 阅读 · 0 评论 -
Effective Modern C++ 条款8:优先考虑nullptr而非0和NULL
但是重复的调用代码——为互斥量上锁,调用函数,解锁互斥量——更令人遗憾。推导为一个错误的类型(即它们的实际类型,而不是作为空指针的隐含意义),这就导致在当你想要一个空指针时,它们的替代品。可以避开了那些令人奇怪的函数重载决议,这不是它的唯一优势。代码虽然可以这样写,但是就像注释中说的,前两个情况不能通过编译。在C++98中,对指针类型和整型进行重载意味着可能导致奇怪的事情。的值的那个)也可以像我们之前讨论的那样被解析。解释为指针,但是那是最后的退路。可以隐式转换为指向任何内置类型的指针,这也是为什么。原创 2024-05-02 22:59:10 · 913 阅读 · 0 评论 -
Effective Modern C++ 条款7:区别使用()和{}创建对象
它的语法能用于各种不同的上下文,它防止了隐式的变窄转换,而且对于C++最令人头疼的解析也天生免疫。取决于你看问题的角度,C++11对象初始化的语法可能会让你觉得丰富的让人难以选择,亦或是乱的一塌糊涂。(注:更灵活的设计——允许调用者决定从模板来的函数应该使用圆括号还是花括号——是有可能的。和构造函数重载的晦涩规则就会一下子涌进你的脑袋,你可能会想研究半天这些东西在你的日常编程中到底占多大比例。)来整合这些混乱且不适于所有情景的初始化语法,所谓统一初始化是指在任何涉及初始化的地方都使用单一的初始化语法。原创 2024-05-02 22:56:57 · 831 阅读 · 0 评论 -
Effective Modern C++ 条款6:auto推导若非己愿,使用显式类型初始化惯用法
当你越熟悉你使用的库的基本设计理念,你的思维就会越活跃,不至于思维僵化认为代理类只能在这些库中使用。很少会出现源代码全都用代理对象,它们通常用于一些函数的返回类型,所以通常能从函数签名中看出它们的存在。出于同样的原因,如果你故意想用整数类型存储一个表达式返回的浮点数类型的结果,你也可以使用这个方法。这样类型的对象的生命期通常不会设计为能活过一条语句,所以创建那样的对象你基本上就走向了违反程序库设计基本假设的道路。不会推导出你想要的类型。)的例子:所谓代理类就是以模仿和增强一些类型的行为为目的而存在的类。原创 2024-04-30 09:14:00 · 974 阅读 · 0 评论 -
Effective Modern C++ 条款5:优先考虑auto而非显式类型声明
中提到的IDE类型显示问题),在很多情况下,少量显示一个对象的类型对于知道对象的确切类型是有帮助的,这通常已经足够了。除了可以避免未初始化的无效变量,省略冗长的声明类型,直接保存闭包外,它还有一个好处是可以避免一个问题,我称之为与类型快捷方式(type shortcuts)有关的问题。在每个循环迭代结束时,临时对象将会销毁,如果你写了这样的一个循环,你可能会对它的一些行为感到非常惊讶,因为你确信你只是让成为。好吧,声明一个局部变量,类型是一个闭包,闭包的类型只有编译器知道,因此我们写不出来,该死!原创 2024-04-30 09:12:34 · 945 阅读 · 0 评论 -
Effective Modern C++ 条款4:学会查看类型推导结果
Item 4: Know how to view deduced types选择使用工具查看类型推导,取决于软件开发过程中你想在哪个阶段显示类型推导信息。我们探究三种方案:在你编辑代码的时候获得类型推导的结果,在编译期间获得结果,在运行时获得结果。在IDE中的代码编辑器通常可以显示程序代码中变量,函数,参数的类型,你只需要简单的把鼠标移到它们的上面,举个例子,有这样的代码中:IDE编辑器可以直接显示推导的结果为,推导的结果为。为此,你的代码必须或多或少的处于可编译状态,因为IDE之所以能提供这些信息是因为原创 2024-04-29 09:35:06 · 790 阅读 · 0 评论 -
Effective Modern C++ 条款3:理解decltype
在这个模板中,我们不知道我们操纵的容器的类型是什么,那意味着我们同样不知道它使用的索引对象(index objects)的类型,对一个未知类型的对象使用传值通常会造成不必要的拷贝,对程序的性能有极大的影响,还会造成对象切片行为(参见。举个例子,假定我们写一个函数,一个形参为容器,一个形参为索引值,这个函数支持使用方括号的方式(也就是使用“这样的代码将会把你送上未定义行为的特快列车,一辆你绝对不想上第二次的车。“符号指出函数的返回类型,尾置返回类型的好处是我们可以在函数返回类型中使用函数形参相关的信息。原创 2024-04-29 09:34:09 · 863 阅读 · 0 评论