Item 5: 多用auto替换显式类型声明
Item 6: 用显示类型声明来避免 auto 的不合适推断
本文所有内容参考于 《Effective Modern C++》(Scott Meyers)一书,仅供个人学习
auto
Item 5:多用auto替换显式类型声明
auto有很多好处:
可以避免未定义的情况:
1 | int x1; // potentially uninitialized |
可以避免繁琐的类型声明,且可以随参数改变:
1 | template<typename It> // 设It是一个迭代器类型 |
在C++14中,还可以在lambda表达式中使用auto:
1 | auto derefUPLess = // comparison func. |
书中提到了std::function 对象:在C++11标准库中,std::function 是一个产生类似于函数指针的模板。与函数指针不同的是,函数指针只能指向函数,而std::function 可以指向所有的可调用对象。如:
1 | std::function<bool(const std::unique_ptr<Widget>&, |
由于 std::function 是一个模板,所以它会比 auto 使用更多的空间。
auto 可以避免不合适的类型声明
比如下面的代码:
1 | std::vector<int> v; |
一般情况下这没有问题,然而 unsigned 和 std::vector<int>::size_type 并不完全一致。
在32位的Windows系统中,两者一致;在64位的 Windows 系统中,unsigned 是32位的,而 std::vector<int>::size_type 是64位的,从而可能导致错误。
再看下面的例子:
1 | std::unordered_map<std::string, int> m; |
是不是一眼看上去并没有错误?然而在 std::unordered_map 中的 key 是 const 类型的,也就是说 pair 应该为 std::pair<const std::string, int>。使用 auto 就能避免这种错误的类型声明。
Things to Remember
- auto variables must be initialized, are generally immune to type mismatches that can lead to portability or efficiency problems, can ease the process of refactoring, and typically require less typing than variables with explicitly specified types.
- auto-typed variables are subject to the pitfalls described in Items 2 and 6.
Item 6:用显示类型声明来避免 auto 的不合适推断
有意思的是,瞎用auto也会导致错误,std::vector<bool> 就是一个典型的例子:
1 | std::vector<bool> features(const Widget& w); |
一般来说,std::vector::operator[] 会返回相应的引用类型,唯独除了 bool 。这是由于C++在实现 vector<bool> 时是根据二进制数某位上的值来得到各个value的,而C++禁止对位的引用,所以 operator[] 会返回 std::vector<bool>::reference 作为替代,它使用起来就和 bool& 类似。然而,在上面的代码中,我们想要的是bool类型而不是 reference ,所以这里应该使用显式的 bool 类型声明。
更进一步的,仔细看上面这段代码,feature(w) 产生了一个临时变量,而 feature(w)[5] 是对这个临时变量的 vector<bool>::reference 。因此,highPriority_auto 实际包含了对这个临时变量的元素的指针,这导致在下一句中, highPriority_auto 包含了一个空指针,从而导致严重错误。
Proxy Class
Proxy class: a class that exists for the purpose of emulating and
augmenting the behavior of some other type. Proxy
类的目的模仿或改进某个类型的行为。如 std::vector<bool>::reference
就是一个proxy class,用来模仿
vector<bool>的operator[],让其看起来像是返回了一个bool&。
智能指针 std::shared_ptr 和 std::unique_ptr 等也是 Proxy class,为了改进
生指针(Raw pointer) 在资源管理上的行为。
说白了,proxy class 的作用就是产生一个代理(proxy),若对含有 proxy class
的代码使用 auto ,很可能会得到 proxy
class的类型而不是看上去直接的类型。
如果非要用 auto 也不是不行:
1 | auto highPriority = static_cast<bool>(features(w)[5]); |
Things to Remember
- “Invisible” proxy types can cause auto to deduce the “wrong” type for an initializing expression.
- The explicitly typed initializer idiom forces auto to deduce the type you want it to have.