C++ 中文周刊 第11期

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

每周更新

周刊项目地址 github在线地址知乎专栏

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


资讯

编译器信息最新动态推荐关注hellogcc公众号

本周周报github直达

文章

介绍几种经典的分配器。这里的不是那种jemalloc那种插件式的,指的是内置型分配器

接上文,讨论了mimalloc的设计

讨论了函数传枚举怎样比较合适, 如果作为参数,有点类似bool flag hell那种问题,作者给了个放在模版参数的方案。比较清晰

没有最佳方案,封装成context结构体也可行,自己选择自己喜欢的写法

#include <iostream>
 
// Enum describing the mode used in the following function
enum class ChangeMode
{
    Before,
    After
};
 
// Function that squares a value and increases it (wether before or after), then prints the result
template<ChangeMode m>
void increase_and_square(int v)
{
    if (m == ChangeMode::Before)
        ++v;
     
    v = v*v;
     
    if (m == ChangeMode::After)
        ++v;
 
    std::cout << v << std::endl; 
}
 
// main function
int main()
{
    const int a = 42;
    increase_and_square<ChangeMode::Before>(a);
    increase_and_square<ChangeMode::After>(a);
}

手把手教你用rr调试(这个例子感觉用gdb也差不多)

讨论修订提案让decltype(auto) 尽可能的隐式move

手把手教你优化代码

std::vector<unsigned> LineOffsets;
LineOffsets.push_back(0);

const unsigned char *Buf = (const unsigned char *)Buffer.data();
const std::size_t BufLen = Buffer.size();

unsigned I = 0;
while (I < BufLen) {
  if (Buf[I] == '\n') {
    LineOffsets.push_back(I + 1);
  } else if (Buf[I] == '\r') {
    // If this is \r\n, skip both characters.
    if (I + 1 < BufLen && Buf[I + 1] == '\n')
      ++I;
    LineOffsets.push_back(I + 1);
  }
  ++I;
}

\r\n出现的频率低,可以用unlikely

可以提前判定\r,加速,用memchr

memchr可以用bithack方法取代

最终patch在这里 https://reviews.llvm.org/D99409

讨论了一种代码场景

bool inRange(int val, int lo, int hi)
    [[pre: lo <= hi]]
{
    return (lo <= val && val <= hi);
}

注意参数是val lo hi,但是偶尔用错了,传参数传成了 lo val hi,这个逻辑就错了

如何解决这种问题?

一种方法是context

struct IntRange { int lo; int hi; };
bool inRange(int val, IntRange r);

assert(inRange({lower, upper}, existingValue)); // compile-time error

assert(inRange(existingValue, {lower, upper})); // OK

作者讨论语义问题,如何提供

return lo <= val <= hi

这种顺序的语义,把参数设定成这样是最好的设计,比如

std::rotate(first, new_first, last)
std::partial_sort(first, output_last, input_last)
std::nth_element(first, pos, last)
std::inplace_merge(first1, last1_also_first2, last2)

但是设计成inrange这种格式就很容易用错

比如std::clamp(value, lo, hi) 这个api作者觉得大概率是抄的opengl里的 接口

如何保证这种格式下,用错了接口,结果也是对的?用min max组合

int oneTrueClamp(int lo, int mid, int hi) {
    return min(max(lo, mid), hi);
}

bool oneTrueInRange(int lo, int mid, int hi) {
    return lo <= mid && mid <= hi;
}

这样mid/lo用错位置,结果也是相同的

这里其实是api设计哲学。这种知识有没有什么书有讲解的?

介绍了一系列Sanitizers ASAN MSAN UBSAN TSAN LSAN

手把手教你用catch2 测试库

觉得c++保持ABI不变过于保守,看向rust那种发展模式,多种abi都支持,并行

还是介绍json库,这个json库有insert_order的功能,这个json标准是不保证的

int main() {
  {
  nlohmann::json json{};
  json["value"] = 42;
  json["array"] = std::array{1, 2, 3};
  std::cout << json.dump(); // prints {"array":[1,2,3],"value":42}
  }

  {
  nlohmann::ordered_json json{};
  json["value"] = 42;
  json["array"] = std::array{1, 2, 3};
  std::cout << json.dump(); // prints {"value":42", array":[1,2,3]}
  }
}

gcc11新加了警告,能查出资源泄漏,如果分配释放不匹配就告警,比如fopen - fclose

讨论了if语句多少能影响到分支预测的性能,代码演示挺有意思的,可以本地玩一玩 代码在这里https://github.com/cloudflare/cloudflare-blog/blob/master/2021-05-branch-prediction

视频

项目


本文永久链接

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