auto

auto
1、减少代码量
2、与std::function相比,更快。
使用auto声明functonal时,auto声明存储一个壁报变量,与该闭包是同一型别的,内存量也和该闭包是一样的。
而使用std::function的时候声明的是一个std::function的实例,不管是什么样都占用固定的尺寸的内存。如果该内存不够用的时候
std::function的构造函数都会分配堆内存来存储闭包。所以std::function比auto更慢。
3、与容器使用时 (unordered_map)

// g++ -o  tt test_auto.cpp -std=c++11
// ./tt
#include <stdio.h>
#include <string>
#include <unordered_map>

#define PRINTLINE                                                              \
  do {                                                                         \
    printf("\n");                                                              \
  } while (0);

int main() {
  std::unordered_map<int, std::string> map1;
  for (auto i = 0; i < 10; i++) {
    map1.insert(std::make_pair(i, std::move(std::to_string(i))));
  }
  for (const std::pair<int, std::string> &p : map1) {
    auto ptr = &p.second;
    printf("%p\t", ptr);
  }
  PRINTLINE
  for (const auto &p : map1) {
    auto ptr = &p.second;
    printf("%p\t", ptr);
  }
}

这段代码的运行结果
我们发现上下两行的地址并不相同
这是unordered_map的键是const的
所以说在for (const std::pair<int, std::string> &p : map1)这个循环中会将
map1本身的std::pair<const int, std::string> 转换成 std::pair<int, std::string>,所以说这个中间就会有一个复制操作。
那么实际上每次都是将p赋值给一个临时变量,然后每次循环结束就会被释放。当你不知道具体类型或者已经知道(但是理解不正确)的时候就最好使用auto.

比如这里如果你明确pair的类型const std::pair<const int, std::string>&p 结果也是一样的

#include <stdio.h>
#include <iostream>
#include <string>
#include <unordered_map>

#define PRINTLINE                                                              \
  do {                                                                         \
    printf("\n");                                                              \
  } while (0);

int main() {
  std::unordered_map<int, std::string> map1;
  for (auto i = 0; i < 10; i++) {
    map1.insert(std::make_pair(i, std::move(std::to_string(i))));
  }
  for (const std::pair<const int, std::string> &p : map1) {
    auto ptr = &p.second;
    printf("%p\t", ptr);
  }
  PRINTLINE
  for (const auto &p : map1) {
    auto ptr = &p.second;
    printf("%p\t", ptr);
  }
  PRINTLINE
}

"代理"型别导致auto推导结果和预期不一样

“代理模式”大家学设计模式都应该知道。常见的代理类有智能指针(std::shared_ptr、std::unique_ptr),std::bitset::reference, std::vector ::reference等。
比如这么一个例子

class Widget { // ... };
std::vector<bool> features(const Widget& w);

用features来返回一个vector 代表w是否满足有个功能。
然后我们选择返回vector 中第五个特质。

bool hightPriority = features(w)[5];

然后我们写一个函数来处理这个特质

processWidget(w, hightPriority);

这样写没问题,但是我如果将这里的显式声明的改成auto

auto hightPriority = features(w)[5];
processWidget(w, hightPriority); // 未定义行为

虽然代码可以编译通过,但是会出现未定义行为。

通常来说std::vector::operator[]会返回一个T&,但是对于std::vector 的情况是一个例外。
它返回的是一个std::vector ::reference型别的对象(这是一个嵌套在std::vector 中的类)。

这是为什么呢?

之所以要弄一个std::vector ::reference,是因为std::vector 做过特化
:使用一种压缩方式来表示每一个bool元素,即用一个bit来表示一个bool元素。然而c++中却禁止bit引用。
怎么说呢?就是本来operator[]返回的是一个bool&,但是实际上返回的却是一个bool&的reference。

那么为什么前一种写法可以呢?

因为前一种写法中,做了一个std::vector ::reference 到std::vector 的隐式转换。
虽然我们使用features返回的是一个std::vector ::reference,但是做了隐式转换后就变成std::vector .

那为什么后一种写法不行呢?

后一种写法中features返回的是一个std::vector ::reference ,使用 auto后,hightPriority,对std::vector ::reference
进行operator[],就不是std::vector 中第5个元素,而是std::vector ::reference中第五个bit

结论

“隐形”代理类和auto无法和平共处。这种类的对象往往会设计维持到单个语句内存在,所以如果要创建这种类的变量,往往就违反了基本库设计的假定前提。
所以我们要防止写出这样的代码

auto someVar = "隐形"代理型别表达式;
所以我们的问题是什么呢?

我们的问题是那些代码中包含有“隐形”代理型别。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值