IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 《Effective Modern C++》学习笔记 - Item 5: 倾向于使用auto而不是显式类型声明 -> 正文阅读

[C++知识库]《Effective Modern C++》学习笔记 - Item 5: 倾向于使用auto而不是显式类型声明

  • 先来定义一个简单的局部变量:
int x; // 糟糕,忘记初始化了。x也许会被初始化为0也许不会,取决于上下文。
  • 别在意。再来定义一个用迭代器(Iterator)解引用初始化的局部变量:
template<typename It>
void dwim(It b, It e)
{
    while (b != e)
    {
    	// 真的假的?声明一个变量这么麻烦?
        typename std::iterator_traits<It>::value_type currValue = *b;
    }
}
  • 事不过三,再举个例子:声明一个闭包的局部变量。坏了,闭包的类型只有编译器知道。
  • 写C++一点都不快乐!(笔者注:原文如此,笑死,加粗表扬)

auto的优势

  • 在C++11,由于 auto 的出现,以上这些问题都不复存在。auto 由initializer推断类型,因此不会出现变量未初始化问题。
auto x1; 		// error!
auto x2 = 0; 	// well-defined.

template<typename It>
void dwim(It b, It e)
{
    while (b != e)
    {
        auto currValue = *b; // 舒服了
    }
}
// 可以表示只由编译器知道的类型
auto derefUPLess =
   [](const std::unique_ptr<Widget>& p1,
      const std::unique_ptr<Widget>& p2)
   { return *p1 < *p2; };
  • 在C++14中,lambda表达式的参数也可以使用 auto
auto derefUPLess =
   [](const auto& p1,
      const auto& p2)
   { return *p1 < *p2; };
  • 你对第三个例子也许会想到使用std::function。概念:C++11对函数指针概念的泛化,可以指向任何可调用的(callable)对象(注:如重载了operator()的类,俗称functor)。声明时在模板中给出指向函数的签名(signature):
// 不使用auto的版本
std::function<bool(const std::unique_ptr<Widget>&,
                   const std::unique_ptr<Widget>&)>
  derefUPLess = [](const std::unique_ptr<Widget>& p1,
                   const std::unique_ptr<Widget>& p2)
                  { return *p1 < *p2; };
// tmd, C++怎么会变成这个样子.jpg
  • 且不论语法上的繁杂性,使用 std::functionauto 是不同的auto 声明的闭包变量其类型就是自身,也只占用闭包需求的内存量。而 std::function 创建的是一个持有闭包对象的 std::function 对象,这通常会占用更多的内存,而且调用速度几乎肯定会更慢。本场比赛中,auto 完胜。

  • auto 的优势还不只如此。以下程序是你可能见过(或者写过的):

std::vector<int> v;
unsigned sz = v.size();
  • v.size() 返回值的正式形式为 std::vector<int>::size_type,然而很少开发者真正了解这一点,而往往认为用 unsigned 足够了。在32位机器上,两者大小相同;然而在64位机器上,前者是64位而后者是32位!
    在这里插入图片描述
  • 注:相信更多人(包括我)更习惯使用 size_t 的写法,这是没有问题的(见下图)。原书中没有提到这一点。
    在这里插入图片描述
  • 显式类型声明可能带来另一种隐患:
std::unordered_map<std::string, int> m;
m.insert(std::make_pair("123", 1));
m.insert(std::make_pair("234", 2));
for (const std::pair<std::string, int>& p : m)
{
    ... // do something with p
}
  • 一眼看上去没什么问题不是吗?但是你可能已经忘记了一个事实:std::unordered_map 的键部分是 const,因此哈希表中的元素不是 std::pair<std::string, int>(声明的 p 的类型),而是 std::pair<const std::string, int>!于是,编译器会想办法将后者转换为前者,并且还真的有一种方案(因此不会报错):把后者复制到一个临时对象,再降其引用赋给 p。这绝对不是你想要的效果。用 auto 可以解决这一切问题:
    在这里插入图片描述

auto的不足

  • Item 2讨论了有时 auto 推断出的类型可能不是你想要的一些情况。
  • auto 可能会带来代码可读性上的问题。IDE的类型提示和命名风格良好的变量名称可以缓解这一问题。
  • 归根结底,auto 只是你的一个可选工具。因此还是要根据实际场景合适地利用其强大功能。

总结

  1. auto 变量必须被初始化,几乎能解决所有移植性和效率上的问题,还能简化代码重构的过程,同时能减少你的打字量。
  2. auto 类型的变量容易掉入Item 2和6所描述的坑中。
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-18 15:47:14  更:2021-12-18 15:47:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 13:22:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码