Item 5:Prefer auto to explicit type declarations
这一条条款全篇都在强调:为什么我们更青睐使用auto
而不是显示类型声明。总得来说,好处有四个:
(1)避免潜在未初始化变量的出现
在C++中有可能因为定义了变量却没有初始化导致错误的结果。而且编译器也不报错。
int x1; //不报错,但潜在的未初始化的变量
auto x2; //错误!必须要初始化
auto x3=0; //没问题,x已经定义了
(2)省略冗长的声明类型
std::map<int,int>::iterator it=mymap.begin(); //复杂
auto it=mymap.begin(); //简单
(3)直接保存闭包
所谓闭包通俗点说就是指lambda表达式、重载运算符、bind表达式。
自从C++11后,我们可以用auto来存储lambda表达式:
auto derefUPLess = [](const std::unique_ptr<Widget> &p1,const std::unique_ptr<Widget> &p2)
{
return *p1<*p2;
};//专用于Widget类型的比较函数
在C++14,lambda表达式也可以使用auto:
auto derefUPLess = [](const auto& p1,const auto& p2)
{
return *p1<*p2;
};
上述例子中,我们使用auto来保存这个闭包(lambda表达式)。如果不使用auto就必须使用std::function
!
std::function
是一个C++11标准模板库中的一个模板,它泛化了函数指针的概念。与函数指针只能指向函数不同,std::function
可以指向任何可调用对象,也就是那些像函数一样能进行调用的东西。当你声明函数指针时你必须指定函数类型(即函数签名),同样当你创建std::function
对象时你也需要提供函数签名
bool(const std::unique_ptr<Widget> &p1,
const std::unique_ptr<Widget> &p2);
就需要使用std::function
这么写:
std::function<bool(const std::unique_ptr<Widget> &p1,
const std::unique_ptr<Widget> &p2)> func;
如果不用auto,上面那么大一坨东西十分繁琐!
(4)避免类型不匹配
这里举两个常见的错误,他们都可以被auto很友好的规避。
错误1:误以为std::vector::size_type
就是unsigned
。
std::vector<int> v;
unsigned sz = v.size();
在Windows 32-bit上std::vector::size_type
和unsigned int
都是一样的类型,但是在Windows 64-bit上std::vector::size_type
是64位,unsigned int
是32位。这意味着这段代码在Windows 32-bit上正常工作,但是当把应用程序移植到Windows 64-bit上时就可能会出现一些问题。
错误2:std::unordered_map
的key是一个常量
std::unordered_map<std::string,int> m;
...
for(const std::pair<std::string,int>& p : m)
{
...
}
由于是常量,所以上面的调用应该改为std::pair
Item 6:Use the explicitly typed initializer idiom when auto deduces undesired types.
auto推断也存在一些问题。
现在有一个函数feature
,传入一个vector
数组,比较每个元素正负,然后返回vector
std::vector<bool> features(vector<int> nums)
{
vector<bool> res;
for (auto x : nums)
res.push_back(x > 0 ? true:false);
return res;
}
现在我想返回数组容器的第5个元素的正负情况,我这么来调用:
auto negative4 = features(nums)[4];
当把鼠标移到negative4
上查看类型时,结果….
vector
的operator[]
的返回值并不是bool类型却变为了std::vector::reference
,这样的话,后面的调用一定会出现奇奇怪怪的问题,这是怎么回事呢?
- 因为
bool
占用一个字节,标准库为了节省内存,改用bit来表示 - 因为
operator[]
需要返回一个内部元素的引用,但是没办法对一个bit进行引用 - 为了让返回的类型统一,无论是bool类型,还是其它类型
此标准库为了实现上述三个目标就封装了一个内部的类型vector::reference
,是一个proxy类(代理类)。其实这个问题指针对于bool
类型,如果是实数类型,不会受到任何影响!
解决的办法是调用显式类型初始器!通过强制转化达成目的。
auto negative4 = static_cast<bool>(features(nums)[4]);