右值引用仅绑定可以移动的对象。如果你有一个右值引用参数,你就知道这个对象可能会被移动: class Widget { Widget(Widget&& rhs); //rhs definitely refers to an object eligible for moving ... }; 这是个例子,你将希望通过可以利用该对象右值性的方式传递给其他使用对象的函数。这样做的方法是将
据说,真相使人自由,然而在特定的环境下,一个精心挑选的谎言也同样使人解放。这一节就是这样一个谎言。因为我们在和软件打交道,然而,让我们避开“谎言(lie)”这个词,不妨说,本节包含了一种“抽象(abstraction)”。 为了声明一个指向某个类型T的右值引用(Rvalue Reference), 你写下了T&&。由此,一个合理的假设是,当你看到一个T&&出现在源码中,你看到的是一个右值引用。唉,
如果你曾经与过多的编译次数斗争过,你会对Pimpl(Pointer to implementation)惯用法很熟悉。 凭借这样一种技巧,你可以将一个类数据成员替换成一个指向包含具体实现的类或结构体的指针, 并将放在主类(primary class)的数据成员们移动到实现类去(implementation class), 而这些数据成员的访问将通过指针间接访问。 举个例子,假如有一个类Widget
让我们先对std::make_unique和std::make_shared做个铺垫。std::make_shared是C++11标准的一部分,但很可惜的是,std::make_unique不是。它从C++14开始加入标准库。如果你在使用C++11,不用担心,一个基础版本的std::make_unique是很容易自己写出的,如下: template<typename T, typename...
自相矛盾的是,如果有一个像std::shared_ptr的指针但是不参与资源所有权共享的指针是很方便的。换句话说,是一个类似std::shared_ptr但不影响对象引用计数的指针。这种类型的智能指针必须要解决一个std::shared_ptr不存在的问题:可能指向已经销毁的对象。一个真正的智能指针应该跟踪所值对象,在悬空时知晓,悬空(dangle)就是指针指向的对象不再存在。这就是对std::w
条款十九:对于共享资源使用std::shared_ptr 程序员使用带垃圾回收的语言指着C++笑看他们如何防止资源泄露。“真是原始啊!”他们嘲笑着说。“你们没有从1960年的Lisp那里得到启发吗,机器应该自己管理资源的生命周期而不应该依赖人类。”C++程序员翻白眼。“你得到的启发就是只有内存算资源,其他资源释放都是非确定性的你知道吗?我们更喜欢通用,可预料的销毁,谢谢你。”但我们的虚张声势可能底
条款九:优先考虑别名声明而非typedefs 我相信每个人都同意使用STL容器是个好主意,并且我希望Item18能说服你让你觉得使用std:unique_ptr也是个好主意,但我猜没有人喜欢写上几次 std::unique_ptr<std::unordered_map<std::string,std::string>>这样的类型,它可能会让你患上腕管综合征的风险大大增加。 避免上述医疗悲剧也很简单
条款八:优先考虑nullptr而非0和NULL 你看这样对不对:字面值0是一个int不是指针。 如果C++发现在当前上下文只能使用指针,它会很不情愿的把0解释为指针,但是那是最后的退路。 一般来说C++的解析策略是把0看做int而不是指针。 实际上,NULL也是这样的。但在NULL的实现细节有些不确定因素, 因为实现被允许给NULL一个除了int之外的整型类型(比如long)。 这不常见,但也算不
条款 17:理解特殊成员函数函数的生成 在C++术语中,特殊成员函数是指C++自己生成的函数。C++98有四个:默认构造函数函数,析构函数,拷贝构造函数,拷贝赋值运算符。这些函数仅在需要的时候才生成,比如某个代码使用它们但是它们没有在类中声明。默认构造函数仅在类完全没有构造函数的时候才生成。(防止编译器为某个类生成构造函数,但是你希望那个构造函数有参数)生成的特殊成员函数是隐式public且inl
条款16: 让const成员函数线程安全 如果我们在数学领域中工作,我们就会发现用一个类表示多项式是很方便的。在这个类中,使用一个函数来计算多项式的根是很有用的。也就是多项式的值为零的时候。这样的一个函数它不会更改多项式。所以,它自然被声明为const函数。 class Polynomial { public: using RootsType = // 数据结构保存
条款 15:尽可能的使用constexpr 如果要给C++11颁一个“最令人困惑新词”奖,constexpr十有八九会折桂。当用于对象上面,它本质上就是const的加强形式,但是当它用于函数上,意思就大不相同了。有必要消除困惑,因为你绝对会用它的,特别是当你发现constexpr “正合吾意”的时候。 从概念上来说,constexpr表明一个值不仅仅是常量,还是编译期可知的。这个表述并不全面,因为
条款 14:如果函数不抛出异常请使用noexcept 在C++98中,异常说明(exception specifications)是喜怒无常的野兽。你不得不写出函数可能抛出的异常类型,如果函数实现有所改变,异常说明也可能需要修改。改变异常说明会影响客户端代码,因为调用者可能依赖原版本的异常说明。编译器不会为函数实现,异常说明和客户端代码中提供一致性保障。大多数程序员最终都认为不值得为C++98的异
条款 13:优先考虑const_iterator而非iterator STL const_iterator等价于指向常量的指针。它们都指向不能被修改的值。标准实践是能加上const就加上,这也指示我们对待const_iterator应该如出一辙。 上面的说法对C++11和C++98都是正确的,但是在C++98中,标准库对const_iterator的支持不是很完整。首先不容易创建它们,其次就算你有
条款12:使用override声明重载函数 在C++面向对象的世界里,涉及的概念有类,继承,虚函数。这个世界最基本的概念是派生类的虚函数重写基类同名函数。令人遗憾的是虚函数重写可能一不小心就错了。给人感觉语言的这一部分设计观点是墨菲定律不是用来遵守的,只是值得尊敬的。 鉴于"重写"听起来像"重载",尽管两者完全不相关,下面就通过一个派生类和基类来说明什么是虚函数重写: class Base {
条款11:优先考虑使用deleted函数而非使用未定义的私有声明 如果你写的代码要被其他人使用,你不想让他们调用某个特殊的函数,你通常不会声明这个函数。无声明,不函数。简简单单!但有时C++会给你自动声明一些函数,如果你想防止客户调用这些函数,事情就不那么简单了。 上述场景见于特殊的成员函数,即当有必要时C++自动生成的那些函数。Item 17 详细讨论了这些函数,但是现在,我们只关心拷贝构造函数