C++ 中文周刊 第68期

reddit/hackernews/lobsters摘抄一些c++动态

周刊项目地址在线地址知乎专栏 腾讯云+社区

欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue

2022年6月25日20:28:48


资讯

标准委员会动态/ide/编译器信息放在这里

六月提案讨论 链接

编译器信息最新动态推荐关注hellogcc公众号 本周更新2022-06-22 第155期

perfbook作者的性能分析挑战赛正在进行中,有空的可以玩一下

文章

int main() {
  auto v = ranges::views::ints | ranges::views::take(2);
  auto o = v | ranges::to<std::vector>();
  assert(std::size(o) == 2 and o[0] == 0 and o[1] == 1);
}

标准库/boost实现的unordered map用的开链表,用的close address,

开链 == close address == table+链表模式

开放定址 == open address == table+数组内probe

优点是迭代访问比较稳定,删除也比较稳定,都是常数。为了满足常数,放弃了高效处理冲突,造成写入慢/空间占用恐怖。不可兼得啊

就是个大数组,bucket大数组,然后数组元素互相用链表串起来

最近boost 1.80 更新了新版本的unordered map,可以看他们的benchmark,性能提升显著(不要和开链法的hashmap比,那肯定被吊锤的)

在这个open address开放定址 的基础上做了性能提升,节省了内存还保持原有语义,如何做到的?

拆分metadata和普通数组, 把bucket大数组抽象成bucket组,每组N个bucket,以组为单位用链表串起来。有那种开闭链结合链表的味了。

然后每组bucket用位运算来定位

承接上文啊,为了erase count O(1)而牺牲掉insert速度真的值得吗,作者做了一个测试,对于unordered_multiset这种可重复key的,发现只要放弃这俩api的效率,insert起码上升五倍。为啥当初那么执着于erase count的效率呢

小编建议不要纠结调整api效率,选用开链的hashmap得了,absl::flat_hash_map

看个乐。以前也说过

这个答案说的方法我恰巧见过一段

https://github.com/PlatformLab/RAMCloud/blob/master/src/Cycles.h

https://github.com/PlatformLab/RAMCloud/blob/master/src/Cycles.cc

这个文章是个系列。经常更新。值得看看

c++23的特性列举一遍。没啥说的了

列举c和c++的一些区别。不要了解。了解会让你痛苦

一段神奇的代码

#include <string>

int table[4];
bool exists_in_table(int v)
{
    for (int i = 0; i <= 4; i++) {
        if (table[i] == v) return true;
    }
    return false;
}

这段代码哪里有问题?聪明的你看到了i越界了。越界应该问题不大,顶多返回个错误的值,所以越界了影响也不大,你要是这么想就错了

编译期视角,i可以越界,越界是未定义行为,未定义行为我他妈怎么搞都可以,那我认为i到不了4,提前返回了,所以这段代码直接优化成 return true,都给编译期懂完了,暖暖的很贴心

exists_in_table(int):
        mov     eax, 1
        ret
table:
        .zero   16

再看这么一段代码

int value_or_fallback(int *p)
{
 return p ? *p : 42;
}

没啥问题,如果我加一行打印呢?

int value_or_fallback(int *p)
{
 printf("The value of *p is %d\n", *p);
 return p ? *p : 42;
}

没有检查p就直接用,编译期一看,你这么写,我太懂你了,p一点没问题是吧,那我还检查p干嘛啊,直接return *p,快谢谢贴心的编译器!

承接上段代码

void unwitting(bool door_is_open)
{
 if (door_is_open) {
  walk_on_in();
 } else {
  ring_bell();
  // wait for the door to open using the fallback value
  fallback = value_or_fallback(nullptr);
  wait_for_door_to_open(fallback);
 }
}

这一点问题都没有吧,调用了value_or_fallback,传个nullptr,你core就完了呗。但贴心的编译器再次出手!编译器说你居然未定义行为了!那说明else永远走不到!我太懂了!直接优化成

void unwitting(bool door_is_open)
{
 walk_on_in();
}

继续,承接上段代码

void keep_checking_door()
{
 for (;;) {
  printf("Is the door open? ");
  fflush(stdout);
  char response;
  if (scanf("%c", &response) != 1) return;
  bool door_is_open = response == 'Y';
  unwitting(door_is_open);
 }
}

因为unwitting走到else会未定义行为,所以door_is_open为false会触发未定义行为,所以编译器太懂你了,door_is_open 为false我直接abort

void keep_checking_door()
{
 for (;;) {
  printf("Is the door open? ");
  fflush(stdout);
  char response;
  if (scanf("%c", &response) != 1) return;
  bool door_is_open = response == 'Y';
  if (!door_is_open) abort();
  walk_on_in();
 }
}

怎么说呢。编译器,听我说,谢谢你,因为有你

写的不错

基础知识普及

了解一下gc知识

写的不错,值得复习复习。

我有点看不懂了

视频

LTO优化二进制。能开都开(MSVC默认开)

这段代码开启LTO/IPO

# Optional IPO. Do not use IPO if it's not supported by compiler.
check_ipo_supported(RESULT result OUTPUT output)
if(result)
  set_property(TARGET foo PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
else()
  message(WARNING "IPO is not supported: ${output}")
endif()

开源项目需要人手

新项目介绍/版本更新

工作招聘

有没有远程接入的工作介绍一下我要被开了


本文永久链接

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持! 觉得写的不错那就给点吧, 在线乞讨 微信转账