C++ 动态新闻推送 第42期

2021-12-18 12:12:33 浏览数 (1)

文章

  • 那些编译器优化盲区 - 1

值得一看,介绍了很多边角优化点。其中无符号判断empty和pointer alias这些我们在之前介绍过。值得再看

  • 【线上问题】P1级公司故障,年终奖不保

bug的代码长这样

代码语言:javascript复制
void AdSort(std::vector<AdItem> &ad_items) {
 std::sort(ad_items.begin(), ad_items.end(), [](const AdItem &item1, const AdItem &item2) {
   if (item1.priority < item2.priority) {
      return true;
    } else if (item1.priority > item2.priority) {
      return false;
    }

    return item1.score >= item2.score;
 } );
}

注意比较要求严格弱序,所以这里的lambda实现有问题

等于应该返回false

这个问题其实算是老生常谈了,搜std::sort coredump能搜到好几个std::sort代码走读/科普严格弱序啥意思的文章。这里就不啰嗦了

  • The Evolutions of Lambdas in C 14, C 17 and C 20

这些年来c lambda的变化

c 14

代码语言:javascript复制
//默认值
auto myLambda1 = [](int x, int y = 0){ std::cout << x << '-' << y << 'n'; };

// 自动推导参数(残废的模版)
auto myLambda = [](auto&& x){ std::cout << x << 'n'; };

//返回一个lambda
auto getMyLambda(int z)
{
    return [z](int x)
           {
               // ...
               // ...
               // ...
           };
}

void f()
{
    // ...
    int z = 42;
    auto myLambda = getMyLambda(z);
    // ...
}

c 17

代码语言:javascript复制
constexpr auto times2 = [] (int n) { return n * 2; };

//拷贝this
struct MyType
{
    int m_value;
    auto getLambda()
    {
        return [self = *this](){ return self.m_value; };
    }
};

c 20

代码语言:javascript复制
// 模版
auto myLambda = []<typename T>(T&& value){ std::cout << value << 'n'; };

//变参模版
template<typename... Ts>
void f(Ts&&... args)
{
    auto myLambda = [...args = std::forward<Ts>(args)](){};
}
  • c tip of week Did you know that static reflection proposal for C 2X has mirror/value based interface?

这个提案看个乐,未必能过

代码语言:javascript复制
template <class T> auto to_string() {
  const auto t = get_aliased(mirror(T));
  std::stringstream str{};
  str << get_name(t) << '{';
  for_each(get_enumerators(t),
    [&str](auto o) { str << get_name(o) << '=' << get_constant(o) << ';'; }
  );
  str << '}';
  return str.str();
}

enum Weekdays {
  Mon = 2,
  Tue = 3,
  Wed = 4,
  Thu = 5,
  Fri = 6,
  Sat = 1,
  Sun = 0
};

int main() {
  std::cout << to_string<Weekdays>(); // prints Weekdays{Mon=2;Tue=3;Wed=4;Thu=5;Fri=6;Sat=1;Sun=0;}
}
  • Little C Standard Library Utility: std::align

通过这个小工具可以轻松写出自己的allocator的aligned_alloc接口

面向的需求是,自定义的一个分配器(比如固定的buffer cache,构造/析构 不释放)可能需要提供alloc还有aligned_alloc

而aligned_alloc很麻烦,要考虑挺多对齐相关的事儿

视频

  • C Weekly - Ep 302 - It’s Not Complicated, It’s std::complex

介绍std::complex

  • Tina Ulbrich - How to rangify your code - Meeting C 2021

介绍他们使用range的经验,实践就是干掉所有for循环,能用range的用range替代

  • Walter E. Brown - Correctly calculating min, max and more - Meeting C online

这个大爷的口音真的很让人犯困,但是这个问题可能很多人没注意 min max 在等于的场景下的语意很模糊

一个简单的实现

代码语言:javascript复制
template<typename T>
const T& min(const T& a, const T& b) {
	return a < b ? a : b;
}

template<typename T>
const T& max(const T& a, const T& b) {
	return a > b ? a : b;
}

如果a等于b ,返回的是b

也许你会说,这又咋了,返回a 返回b有啥区别呢?简单int之类scalar type的确实没啥区别

给个例子

代码语言:javascript复制
struct student {
  std::string name;
  int id;
  inline static int regist = 0;
  student(std::string n) : name(n), id(regist  ) {}
  bool operator <(student s) const {
    return name < s.name;
  }
}

如果比较student 哪个小 明明student a b 的id绝对是不同的,但是永远返回了b,区分不清 a b的场景,

那如果求最大值,是不是应该返回a,这样才能区分

这就是这个两个接口的问题

行为要互补

另外,需要对比较的对象做一个约束(concept)一直递增,这样就能更好的描述这两个接口

所以实现就这个样子

代码语言:javascript复制
inline bool out_of_order(... a, ... b) { return b<a;}
template<typename T>
const T& min(const T& a, const T& b) {
	return out_of_order(a, b) ? b : a;
}

template<typename T>
const T& max(const T& a, const T& b) {
	return out_of_order(a, b) ? a : b;
}

引申一下,这个约束叫啥呢?严格全序? 引入std::range::less

这个视频非常值得一看,把compare讲的明明白白

项目

  • parlaylib并行算法工具箱
  • mold 发布正式版1.0,之前我们介绍过,是一个非常牛的 linker,速度快
  • cpp-rrb 一个RRB-tree实现,尽管 immer.库有个类似的immer::flex_vector
  • TLM 一个检测线程死锁的库

一个简单例子

代码语言:javascript复制
#include "thread_monitor/thread_monitor.h"

void myLivelockedMethod();

void myParentMethod() {
  thread_monitor::ThreadMonitor<> monitor("Livelock demo", 1);

  std::this_thread::sleep_for(2ms);
  thread_monitor::threadMonitorCheckpoint(2);
  myLivelockedMethod();
}

void myLivelockedMethod() {
  thread_monitor::threadMonitorCheckpoint(3);

  while (true) {
      std::this_thread::sleep_for(1ms);
  }
}

明显的死循环,过一段时间,monitor就会吧这个打印出来

代码语言:javascript复制
Frozen thread: Livelock demo id: 140085845083904
Checkpoint: 1   at: 2021-12-09 23:29:36.201542  delta: 0 us
Checkpoint: 2   at: 2021-12-09 23:29:36.203625  delta: 2083 us

原理就是有个队列记录状态,状态长时间不更新就打印

如果你把thread_monitor::threadMonitorCheckpoint(4);放到while循环内部,就永远不会触发frozen打印

用来做个debug还是够用的

  • libtree

将ldd的显示列成tree的形式

0 人点赞