C++ 中文周刊 第104期

2023-03-11 09:48:36 浏览数 (1)

C 中文周刊 第104期

RSS https://github.com/wanghenshui/cppweeklynews/releases.atom

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

请提交 issue

这周瞎忙一周,没来得及看


资讯

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

编译器信息最新动态推荐关注hellogcc公众号 本周更新 2023-03-08 第192期

文章

  • 一场由私有继承enable_shared_from_this引发的血案

TL;DR 使用enable_shared_from_this 一定要public继承

  • 全面解析brpc 之 bthread(2):TaskMeta
  • 全面解析brpc 之 bthread(3):TaskGroup
  • 全面解析brpc 之 bthread(4):TaskControl
  • 全面解析brpc之 bthread(6):butex
  • 全面解析brpc之 bthread(7):总结

一波源码解读,brpc大家都懂懂,争取抄一个自己的rpc

  • 每(几)天学一点 C Execution(一)
  • 每(几)天学一点C Execution(二)
  • 每(几)天学一点 C Execution(三)
  • 每(几)天学一点 C Execution(四

空大讲execution的文章,感兴趣的看看

  • Float-parsing benchmark: Regular Visual Studio, ClangCL and Linux GCC

Daniel Lemire我觉得他的名字应该没人不知道吧。已经提及过很多次,性能专家

std::from_chars已经要比strtod快很多倍了,作者的fast_floatstd::from_chars还快

(前身是fast_double_parser,没切的建议切过去,API和std::from_chars相同)

这篇文章是案例顺带压测一下速度。不用看也知道是吊锤,这个库很多软件都用,比如clickhouse

  • Did you know about intrisincts to support SIMD (Single Instruction, Multiple Data) instructions?

就是SIMD 接口。没啥说的

代码语言:javascript复制
#include <immintrin.h>

int main() {
    const std::vector a = {1, 2, 3, 4};
    const std::vector b = {5, 6, 7, 8};

    const auto va = _mm_loadu_si128((__m128i*)a.data());
    const auto vb = _mm_loadu_si128((__m128i*)b.data());
    const auto result = _mm_add_epi32(va, vb);

    std::vector<int> v(a.size());
    _mm_storeu_si128((__m128i*)v.data(), result);

    assert((std::vector{1   5, 2   6, 3   7, 4   8} == v));
}
  • STL algorithms for trivial relocation

讲trivial relocation的现状以及开源实现

T.r. types

Non-t.r. types

Throwing-move types

Rightward motion (`insert`)

Leftward motion (`erase`)

Non-pointer iterators

STL Classic (non-relocating)

std::copy

N/A

N/A

UB

std::copy_n

N/A

N/A

UB

UB

std::copy_backward

N/A

N/A

UB

cstring

memcpy

UB

UB

UB

SFINAE

memmove

UB

SFINAE

Qt

q_uninitialized_relocate_n

✓?

UB

UB

SFINAE

q_relocate_overlap_n

SFINAE

BSL

destructiveMove

UB

UB

SFINAE

P2786R0

trivially_relocate

SFINAE

SFINAE

SFINAE

relocate

SFINAE

SFINAE

move_and_destroy

SFINAE

UB

?

P1144R6

uninitialized_relocate

UB

uninitialized_relocate_n

UB

P1144R7

uninitialized_relocate_backward

UB

还给人folly提MR https://github.com/facebook/folly/pull/1934

这是个挺复杂的话题。了解一波

  • Update on my trivial swap prize offer

还是和trivial relocation相关的实现问题。看不懂

  • Idioms for Polymorphism and Templates

一些模版技巧介绍

CRTP没人不知道吧,想想enable_shared_from_this

overload用法,也就这么个例子

代码语言:javascript复制
template<typename ... Ts> 
struct Overload : Ts ... { 
    using Ts::operator() ... ; 
};

策略模版,比如

代码语言:javascript复制
template<class T, class Allocator std::allocator<T>>        
class vector; 

template<class Key,
    class T,
    class Hash = std::hash<Key>,                               
    class KeyEqual = std::equal_to<Key>,                       
    class allocator = std::allocator<std::pair<const Key, T>>  
class unordered_map;

Tag Dispatching 想想迭代器特化

Type Erasure 想想std::function,之前咱们也手挫过一个,往前翻翻回忆一下

  • The decorator pattern and binary sizes

先列一段装饰器模式的代码,其实就是策略模式

代码语言:javascript复制
// taxed.h

#pragma once

#include "money.h"
#include "priced_item.h"
#include <utility>

template< int taxRate, PricedItem Item >
class Taxed : private Item  // Using inheritance
{
 public:
   template< typename... Args >
   explicit Taxed( Args&&... args )
      : Item{ std::forward<Args>(args)... }
   {}

   Money price() const {
      return Item::price() * ( 1.0   (taxRate/100) );
   }
};

// priced_item.h

#pragma once

#include "money.h"

template< typename T >
concept PricedItem =
   requires ( T item ) {
      { item.price() } -> std::same_as<Money>;
   };

// money.h

#pragma once

#include <cmath>
#include <concepts>
#include <cstdint>
#include <ostream>

struct Money
{
   uint64_t value{};
};

template< typename T >
   requires std::is_arithmetic_v<T>
Money operator*( Money money, T factor )
{
   return Money{ static_cast<uint64_t>( money.value * factor ) };
}

constexpr Money operator ( Money lhs, Money rhs ) noexcept
{
   return Money{ lhs.value   rhs.value };
}

std::ostream& operator<<( std::ostream& os, Money money )
{
   return os << money.value;
}

// discounted.h

#pragma once

#include "money.h"
#include "priced_item.h"
#include <utility>

template< int discount, PricedItem Item >
class Discounted  // Using composition
{
 public:
   template< typename... Args >
   explicit Discounted( Args&&... args )
      : item_{ std::forward<Args>(args)... }
   {}

   Money price() const {
      return item_.price() * ( 1.0 - (discount/100) );
   }

 private:
   Item item_;
};

// cpp_book.h

#pragma once

#include "money.h"

#include <string>
#include <utility>

class CppBook
{
 public:
   CppBook( std::string name, Money price )
      : name_{ std::move(name) }
      , price_{ price }
   {}

   std::string const& name() const { return name_; }
   Money price() const { return price_; }

 private:
   std::string name_;
   Money price_;
};

// main.cpp

#include "conference_ticket.h"
#include "cpp_book.h"
#include "discounted.h"
#include "taxed.h"

#include <cstdlib>



int main()
{
   // 20% discount, 15% tax: (499*0.8)*1.15 = 459.08
   Taxed<15,Discounted<20,ConferenceTicket>> item{ "Core C  ", Money{499} };
   Taxed<16,Discounted<21,ConferenceTicket>> item2{ "Core C  ", Money{499} };
   Taxed<17,Discounted<22,CppBook>> item3{ "Core C  ", Money{499} };

   Money const totalPrice = item.price();  // Results in 459.08
   Money const totalPrice2 = item2.price();
   Money const totalPrice3 = item3.price();
      // ...

   return EXIT_SUCCESS;
}   

比继承快多了

  • std::string now supports Address Sanitizer

MSVC的能力介绍

  • When Debug Symbols Get Large

chrome编译符号太大了。只能升级工具来解决这个问题。作者的吐槽文

  • Composing callables in modern C

组合函数,高阶函数,一个常规的写法

代码语言:javascript复制
template <class F, class... Fs> 
constexpr auto compose(F &&arg, Fs &&...args) {
  return [
    fun = std::forward<F>(arg),
    ... functions = std::forward<Fs>(args)
  ] <class... Xs> (Xs &&...xs) mutable
    requires std::invocable<F, Xs...> {
    if constexpr (sizeof...(Fs)) {
      return compose(std::forward<Fs>(functions)...)(
        std::invoke(std::forward<F>(fun), 
                    std::forward<Xs>(xs)...));
    } else {
      return std::invoke(
        std::forward<F>(fun), 
        std::forward<Xs>(xs)...);
    }
  };
}

辣眼睛。有没有人类能看懂的?std::views::transform

代码语言:javascript复制
using std::views::transform;
auto fgh = transform(h) | transform(g) | transform(f);
 
// Calculate f( g( h(x) ) )
auto fgh_x = ranges::single_view{42} | fgh; 
 
//fgh_x[0]

豁然开朗了家人们

代码语言:javascript复制
template <class... Fs>
auto composer(Fs&&... functions) {
  using std::views::transform;
  return (transform(functions) | ...);
}
  • Merging intervals in next-gen C

leetcode 56题,用stl算法怎么做?std::partial_sum

代码语言:javascript复制
sort(intervals);
auto merged = views::partial_sum(intervals, [](auto curr, auto i){
    return curr.second >= i.first ? std::pair{curr.first, max(curr.second, i.second)} : i;
}) | views::adjacent_remove_if([](auto i1, auto i2){
    return i1.first == i2.first;
});
 
for (const auto& [i,j] : merged) {
    std::cout << i << " " << j << "n";
}
  • SWAR find any byte from set

很精彩的讲SWAR的文章,我还没有看完

  • The Little Things: Why you should always have benchmarks ready

hyperfine可以分析单测执行快慢。建议执行单测可以前面加上这个跑,每次统计测试运行时间长短,来分析代码哪里引入问题,这也是一个有趣的思路

总之测试压测之类的数据,都是有用的

代码分析慢的地方是结构体比较 opetator==慢了。这个没啥好讲的,主要在于前面发现问题的思路,提前发现问题,解决问题

  • Effortless Performance Improvements in C : std::vector

老生常谈了。reserve提高局部性,改动只要一点点

代码语言:javascript复制
 std::vector<std::string> tokenize(const std::string& s)
 {
   std::vector<std::string> result;
   // Expect four fields or less in our input.
   result.reserve(4);
   std::string::size_type f = 0;
   std::string::size_type p = s.find(':');

开源项目需要人手

  • asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
  • pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线
  • Unilang deepin的一个通用编程语言,点子有点意思,也缺人,感兴趣的可以github讨论区或者deepin论坛看一看。这里也挂着长期推荐了
  • paozhu 国人开发的web库,和drogon联系过没共建而考虑自己的需求基于asio开发。感兴趣的可以体验一下,挂在这里长期推荐了

新项目介绍/版本更新

  • snitch 又一个测试框架,我怎么感觉我说过

0 人点赞