Skip to content

Releases: wanghenshui/cppweeklynews

C++ 中文周刊 第102期

24 Feb 12:35
95529af
Compare
Choose a tag to compare

周刊项目地址

公众号

弄了个qq频道,手机qq点击进入

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

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

提交 issue

本周内容我没有细看。有些值得展开说说


资讯

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

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

本月邮件列表 https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/#mailing2023-02

文章

constexpr size_t Rows = 5;
const std::map<std::string, std::array<double, Rows>> productToOrders{
        { "apples", {100, 200, 50.5, 30, 10}},
        { "bananas", {80, 10, 100, 120, 70}},
        { "carrots", {130, 75, 25, 64.5, 128}},
        { "tomatoes", {70, 100, 170, 80, 90}}
};

// print headers:
for (const auto& [key, val] : productsToOrders)
    std::cout << std::setw(10) << key;
std::cout << '\n';

// print values:
for (size_t i = 0; i < NumRows; ++i) {
    for (const auto& [key, val] : productsToOrders) {
        std::cout << std::setw(10) << std::fixed 
                  << std::setprecision(2) << val[i];
    }
    std::cout << '\n';
}

template <typename T>
size_t MaxKeyLength(const std::map<std::string, T>& m) {
    size_t maxLen = 0;
    for (const auto& [key, val] : m)
        if (key.length() > maxLen)
            maxLen = key.length();
    return maxLen;
}
const auto ColLength = MaxKeyLength(productsToOrders) + 2;

// print values:
for (size_t i = 0; i < NumRows; ++i) {
    for (const auto& values : std::views::values(productsToOrders)) {
        std::cout << std::format("{:>{}.2f}", values[i], ColLength);
    }
    std::cout << '\n';
}
/*
****apples***bananas***carrots**tomatoes
    100.00     80.00    130.00     70.00
    200.00     10.00     75.00    100.00
     50.50    100.00     25.00    170.00
     30.00    120.00     64.50     80.00
     10.00     70.00    128.00     90.00
*/

没啥说的

if里面的条件判断,最好外面算好再放进if里

if ((_someLongNamedVar != FooLongNameEnum::Unknown && _someLongNamedMap.count   (_someLongNamedVar) == 0))

改成

bool someLongNamedVarIsNotUnknown = _parameterCommand != FooLongNameEnum::Unknown;
bool someLongNamedMapCountIsZero = _someLongNamedMap.count(_someLongNamedVar) == 0

提高可读性,关爱同事

一些c的边角邪门歪道。只有特殊场景能用到,比如位域

struct cat {
    unsigned int legs  : 3;  // 3 bits for legs  (0-4 fit in 3 bits)
    unsigned int lives : 4;  // 4 bits for lives (0-9 fit in 4 bits)
};

struct bar {
    unsigned char x : 5;
    unsigned short  : 0; // 帮你padding
    unsigned char y : 7;
}

就不逐一介绍了

struct interface {
    constexpr virtual ~interface() = default;
    constexpr virtual auto get() const -> int = 0;
};

struct implementation final : interface {
    constexpr explicit(true) implementation(int value) : value{value} {}
    constexpr auto get() const -> int { return value; }

private:
    int value{};
};

constexpr auto foo(auto value) {
    std::unique_ptr<interface> i = std::make_unique<implementation>(value);
    return i->get();
}

static_assert(42 == foo(42));

逆天

void MyClass::DoSomething() {
    try {
        auto name = m_user.GetName();
        m_label.Text(name);
    } catch (...) {
        m_label.Text(L"unknown");
    }
}

如果m_label.Text(L"unknown");异常,怎么办?

一种猥琐的角度

winrt::fire_and_forget MyClass::DoSomethingAsync()
{
    auto lifetime = get_strong();
    try {
        auto name = co_await m_user.GetNameAsync();
        m_label.Text(name);
    } catch (...) {
        try {
            m_label.Text(L"unknown");
        } catch (...) {
            LOG_CAUGHT_EXCEPTION();
        }
    }
}

你就说catch没catch住吧,别管几个if

或者,不太常见的写法

winrt::fire_and_forget MyClass::DoSomethingAsync() try
{
    auto lifetime = get_strong();
    try {
        auto name = co_await m_user.GetNameAsync();
        m_label.Text(name);
    } catch (...) {
        m_label.Text(L"unknown");
    }
} catch (...) {
    // The function is best-effort. Ignore failures.
}

你学废了吗

说实话,我不是很懂。值得研究一波

教你使用opentelemetry

介绍文档工具和github action集成

还是实验性质。感觉没人用

图形生成?高游戏的?我不是很懂

讲解magic_enum原理

看不懂

视频

还是__buildin_dump_struct实现。循序渐进。可以看看。我周末传b站一份

这个也很有意思,值得研究研究。我周末传b站一份

开源项目需要人手

  • asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
    最近写了很多高科技,比如https://github.com/lhmouse/asteria/blob/master/rocket/ascii_numget.hpp 很多细节考量

  • pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线
    有很多的issue task没人做,想参与开源项目开发的,来练练手

新项目介绍/版本更新

工作招聘

有想打广告的可以发给我。五毛一条


看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持!

本文永久链接

如果有疑问评论最好在上面链接到评论区里评论,这样方便搜索,微信公众号有点封闭/知乎吞评论

C++ 中文周刊 第101期

17 Feb 12:37
fe88063
Compare
Choose a tag to compare

周刊项目地址

公众号

弄了个qq频道,手机qq点击进入

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

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

提交 issue

最近有点忙,看的不是很细

资讯

之前聊过很多次的perf book,有中文版本了,中文名 现代CPU性能分析与优化

https://item.m.jd.com/product/10068178465763.html

这里没有带货的意思嗷,英语比较熟的,可以在这里免费获取这本书

https://book.easyperf.net/perf_book 填一下邮箱就会发给你邮件

​如果不熟,支持中文书也可以买一下。不过我感觉新书刚上有点贵了,一般来说三月末有个读书节之类的活动,有打折,可以到时候再买。

另外就是有没有出版社大哥能不能赞助两本我抽了,没有我就三月底自己买来抽了


A call to action:Think seriously about “safety”; then do something sensible about it

针对NSA的c++不安全的说法,BS慌了。和大家讨论一下改进措施

另外这里也吵翻天了 C++ 之父为什么说 Rust 等内存安全语言的安全性并不优于 C++? https://www.zhihu.com/question/584122632

C++23 “Pandemic Edition” is complete (Trip report: Winter ISO C++ standards meeting, Issaquah, WA, USA)

草药老师发了开会总结

AMD RDNA™ 3 指令集架构 (ISA) 参考指南现已推出

用了新显卡的关注下

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

文章

enum的周边设施,std::is_enum std::underlying_type std::is_scoped_enum std::to_underlying

UE教程

std::initializer_list<int> wrong() { // for illustration only!
    return { 1, 2, 3, 4};
}
int main() {
    std::initializer_list<int> x = wrong();
}

初始化列表的坑爹之处,生命周期有问题,别这么写。没关系,编译器会告警的。你说你不看告警?

算字符串占多少

size_t scalar_utf8_length(const char * c, size_t len) {
  size_t answer = 0;
  for(size_t i = 0; i<len; i++) {
    if((c[i]>>7)) { answer++;}
  }
  return answer + len;
}

显然,可以SIMD

size_t avx2_utf8_length_basic(const uint8_t *str, size_t len) {
  size_t answer = len / sizeof(__m256i) * sizeof(__m256i);
  size_t i;
  for (i = 0; i + sizeof(__m256i) <= len; i += 32) {
    __m256i input = _mm256_loadu_si256((const __m256i *)(str + i));
   answer += __builtin_popcount(_mm256_movemask_epi8(input));
  }
  return answer + scalar_utf8_length(str + i, len - i);
}

优化一下

ize_t avx2_utf8_length_mkl(const uint8_t *str, size_t len) {
  size_t answer = len / sizeof(__m256i) * sizeof(__m256i);
  size_t i = 0;
  __m256i four_64bits = _mm256_setzero_si256();
  while (i + sizeof(__m256i) <= len) {
    __m256i runner = _mm256_setzero_si256();
    size_t iterations = (len - i) / sizeof(__m256i);
    if (iterations > 255) { iterations = 255; }
    size_t max_i = i + iterations * sizeof(__m256i) - sizeof(__m256i);
    for (; i <= max_i; i += sizeof(__m256i)) {
      __m256i input = _mm256_loadu_si256((const __m256i *)(str + i));
      runner = _mm256_sub_epi8(
        runner, _mm256_cmpgt_epi8(_mm256_setzero_si256(), input));
    }
    four_64bits = _mm256_add_epi64(four_64bits, 
      _mm256_sad_epu8(runner, _mm256_setzero_si256()));
  }
  answer += _mm256_extract_epi64(four_64bits, 0) +
    _mm256_extract_epi64(four_64bits, 1) +
    _mm256_extract_epi64(four_64bits, 2) +
    _mm256_extract_epi64(four_64bits, 3);
    return answer + scalar_utf8_length(str + i, len - i);
}

代码在这 https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/tree/master/2023/02/16 我已经看不懂了

帮你抓安全问题

LLVM变动,不懂不评价

llvm变动,没细看,不过使用libc++可以白捡这个llvm优化,人家clickhouse都用上了

module体验

这个概念是需要掌握的。虚拟地址,页表等等

手把手教你渲染个飞机

MaskRay写完UBsan介绍又写这个了。笔耕不辍这是

聪明的你肯定想到了还原堆栈要怎么做。汇编我看不懂,你比我聪明

论文。实现个checker

聪明的你肯定想到了pthread_cancel以及SIG_CANCEL,然后怎么实现??

评审c代码的一些经验

比如 assert

#define ASSERT(c) if (!(c)) __builtin_trap()

再比如

char *s = ...;
if (isdigit(s[0] & 255)) {
    ...
}

为什么不能直接用?

或者直接用这玩意

_Bool xisdigit(char c)
{
    return c>='0' && c<='9';
}

还有setjmp and longjmp 信号atomic之类的。都没细说。总之谨慎

讲了几个其他语言优化更好的点,替换c++。没啥说的。都能替

@wu-hanqing 投稿。咱们之前在94期也提到过,就是shared_ptr有个别名构造。别用。很坑。鼓励大家投稿。不然显得我玩单机互联网

template<class T>
concept foo_like = requires(T t) { t.foo; };

template<auto Concept>
struct foo {
  auto fn(auto f) {
    static_assert(requires { Concept(f); });
  }
};

int main() {
  foo<[](foo_like auto){}> f{};

  struct { int foo{}; } foo;
  struct { } bar;

  f.fn(foo); // ok
  f.fn(bar); // error: contrain not satisfied
}

注意这个concept套娃用法,通过lambda绕进去

我觉得还是看个乐。这玩意以后肯定不能这么写,过于邪门歪道

还不懂?再看一遍

这个定位非常非常非常精彩

首先,perf

 	
sudo perf stat -C8 --timeout 10000

火焰图

git clone https://github.com/brendangregg/FlameGraph
git -C FlameGraph remote add adamnovak https://github.com/adamnovak/FlameGraph
git -C FlameGraph fetch adamnovak
git -C FlameGraph cherry-pick 7ff8d4c6b1f7c4165254ad8ae262f82668c0c13b # C++ template display fix
 
x=remote
sudo timeout 10 perf record --call-graph=fp -C8 -o $x.data
sudo perf script -i $x.data > $x.perf
FlameGraph/stackcollapse-perf.pl $x.perf > $x.folded
FlameGraph/flamegraph.pl $x.folded > $x.svg

查到 compact_radix_tree::tree::get_at() and database::apply(). 有问题

sudo perf annotate -i $x.data

代码已经找到,但是为啥??

查事件

sudo perf stat --timeout 1000000 -C8 ...events... -x\t 2>&1 | sed 's/<not counted>/0/g'

需要关注的事件

CPU_CYCLES, obviously, because we were doing the measurement for the same amount of time in both cases.
LDREX_SPEC “exclusive operation speculatively executed” — but since it happens only 1,000 times per second, it can’t possibly be the cause.
EXC_UNDEF “number of undefined exceptions taken locally” — I don’t even know what this means, but it doesn’t seem like a reasonable bottleneck.
STALL_BACKEND only supports our suspicion that the CPU is bottlenecked on memory somehow.
REMOTE_ACCESS

REMOTE_ACCESS明显离谱了,seastar已经绑核,哪里来的跨核访问???

程序本身的静态数据跨核了????

sudo cat /proc/$(pgrep -x scylla)/numa_maps
N0=x N1=y means that x pages in the address range are allocated on node 0 and y pages are allocated on node 1. By cross-referencing readelf --headers /opt/scylladb/libexec/scylla we can determine that .text, .rodata and other read-only sections are on node 0, while .data, .bss and other writable sections are on node 1.

发现这几个段不在一个核??不应该啊

强制绑核,发现问题确实如此 /usr/bin/numactl --membind 1 to /usr/bin/scylla scylla_args…:

用mbind分析为什么,发现了一个page有共享问题,那就是cacheline颠簸了

Using this ability, we discover that only one page matters: 0x28c0000, which contains .data, .got.plt and the beginning of .bss. When this page is on node 1, the run is slow, even if all other pages are on node 0. When it’s on node 0, the run is fast, even if all other pages are on node 1.

尝试改二进制,加padding,解决了??根因是什么?怎么加padding?

We can move the suspicious area by stuffing some padding before it. .tm_clone_table seems like a good enough place to do that. We can add an array in .tm_cl...
Read more

C++ 中文周刊 第100期

10 Feb 11:44
15989be
Compare
Choose a tag to compare

周刊项目地址

公众号

弄了个qq频道,手机qq点击进入

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

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

提交 issue

本周内容不多


资讯

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

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

关于标准委员会的吵架动态,可以看 https://www.zhihu.com/people/mick235711 的动态。这里就不转发了

文章

360发布了他们的代码安全规范,还是值得一看的,UB描述了很多

一段到处都在传播的代码

#include <iostream>
int main() {
  while(1)
  ;
}

void unreachable() {
  std::cout << "hello world\n";
}

clang会打印hello world而gcc/msvc不会,为啥??

简单来说是没用到的死循环直接给删了,然后没有ret,直接跳到下一个函数了

这也是UB的一种。感兴趣的可以点进去看看

-O3 -flto 性能起码提升5%,后续引入PGO继续探索。PGO还是很值得研究的,针对业务来优化效率更高

static_assert(0 == std::rank_v<void>);
static_assert(0 == std::rank_v<int>);
static_assert(1 == std::rank_v<int[]>);
static_assert(0 == std::rank_v<int[0]>);
static_assert(1 == std::rank_v<int[1]>);
static_assert(1 == std::rank_v<int[42]>);
static_assert(2 == std::rank_v<int[][2]>);
static_assert(2 == std::rank_v<int[1][2]>);
static_assert(3 == std::rank_v<int[1][2][3]>);

数组的维度,这玩意和向量的秩英文名一样啊。。

如何实现?

#include <type_traits>

template<class T>
struct prev;

template<class T, int N>
struct prev<T[N]> : std::type_identity<T> {};

template<class T>
struct prev<T[]> : std::type_identity<T> {};

template<class T>
constexpr auto return_rank()
{
    if constexpr (::std::is_array_v<T>) {
        return return_rank<typename prev<T>::type>() + 1;
    }
    return 0;
}

template<class T>
constexpr auto rank_v = return_rank<T>();

QML_DISABLE_DISK_CACHE=1 加速 QML编译

省流:可以

又是WinAPI,我看不懂不多逼逼

浮点数比较,很烦

bool cmpEq(double a, double b, 
  double epsilon = 1e-7, double abstol = 1e-12)
{
  if (a == b) { // 判断inf用的,傻逼inf
    return true;
  }
  double diff = std::fabs(a - b);
  double reltol = std::max(std::fabs(a),
    std::fabs(b)) * epsilon;
  return diff < reltol || diff < abstol;
}

家人们还是看看远处的boost实现吧 https://www.boost.org/doc/libs/1_81_0/boost/test/tools/floating_point_comparison.hpp

寄存器,用eax, ebx, ecx, edx, ebp, esp, esi, edi, r8, r9, r10, r11, r12, r13, r14, r15 ,rax eax宽度区别

传参数,用 rdi, rsi, rdx, rcx, r8 r9, 放不下放栈上

来个例子

long myfunc(long a, long b, long c, long d,
            long e, long f, long g, long h)
{
  long xx = a * b * c * d * e * f * g * h;
  long yy = a + b + c + d + e + f + g + h;
  long zz = utilfunc(xx, yy, xx % yy);
  return zz + 20;
}

rbp 大家也都懂,也会优化掉,因为可以根据rsp算出来。-fno-omit-frame-pointer可以保留

看不懂

书评。没看到书没啥说的

测了一些软件用O3编译二进制大了点,但性能都有提升

视频

最近没啥看的

开源项目需要人手

  • asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
  • pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线

新项目介绍/版本更新


看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持!

本文永久链接

如果有疑问评论最好在上面链接到评论区里评论,这样方便搜索,微信公众号有点封闭/知乎吞评论

C++ 中文周刊 第99期

03 Feb 13:02
7689dd2
Compare
Choose a tag to compare

周刊项目地址

公众号

弄了个qq频道,手机qq点击进入

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

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

提交 issue

20230203


资讯

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

编译器信息最新动态推荐关注hellogcc公众号 2023-02-01 第187期

有武汉线下活动,可以关注

fishshell这个项目宣布用rust重写了。理由是c++太差了周边编译设施等等太难用了之类的

对此笔者锐评:确实

reddit社区对此锐评: Stop Comparing Rust to Old C++

我觉得有点露怯了,实话实说,构建确实不好用,演进也慢,你说meson conan能用我只能说还差点意思

而且c++开源社区开发人员也差点意思,没那个功夫,但rust就很不一样,很多人愿意拿rust练手。

只能说c++周边的演进还需要加快一些。周边文章咨询写的多一些,更通俗易懂一些,知道的人越多越好。大家多写文章多分享啊

本周还有一个事情是yandex的代码泄露,磁力链接在这个答案可以看到,https://www.zhihu.com/question/580980335/answer/2867507106

这两天看了下,cpp的项目挺有意思,但两个组件库util和mapreduce是没泄露的,比较可惜,要是都泄露了我就要创业了

不过一个成熟的引擎,数据是最重要的,没有数据,工具没啥意义。

他们的代码接口风格还是98那套Interface形式,但是都用的pragram once,没用Macro Guard,给人一种老太太用神仙水的反差感

另外有人问为啥他们数据库代码没泄露。。他们用的ydb本身就是开源的。

文章

jetbrains出的报告,关于c++20使用,编译工具cmake使用率,代码分析使用率做了个列举,这里直接贴一下

构建工具,cmake越来越普及,虽然难用

什么?你想问包管理工具?

嘻嘻,没人用

用什么测试框架?

甚至不写测试

使用什么代码分析工具?

嘻嘻,甚至不用分析工具

完整报告可以去他们官网看。这里不列举了

其实就是链式构造啦

template<typename This>
struct ToggleBuilder {
    template<typename... T>
    auto& When(bool flag, auto f, T&&... params)
    {
        auto& actualThis = static_cast<This&>(*this);
        if (flag)
        {
            std::invoke(f, actualThis, std::forward<T>(params)...);
        }
        return actualThis;
    }
};
 
class MessageBuilder : public ToggleBuilder<MessageBuilder> {
   MessageBuilder& WithPayload(std::string payload)
    {
        m_payload = std::move(payload);
        return *this;
    }
     
    //...
};

Message CreateMessage(std::string payload, const Config& config)
{
    return MessageBuilder{}
        WithPayload(std::move(payload)).        
        When(config.someSpecialRecipeEnabled, [](MessageBuilder& builder){ 
            return builder.WithAppender(GetSpecialAppenderParams()).
                           WithAppender(GetAnotherSpecialAppenderParams());
        }).
        // ...
        .Build();
}

来个现实生活中的例子,OnnxRuntime

auto session = SessionBuilder{}.
    WithLogger(MakeLoggerFrom(config)).
    WithModel(config.modelPath).
    WithCUDAExecutionProvider(config.cudaOptions).
    WithOpenVINOExecutionProvider(config.openVinoOptions).
    WithOptimizationLevel(config.optimizationLevel).
    WithNumberOfIntraThreads(config.intraThreads).
    //...
    Build();

用上面那个设计,相当于

auto session = SessionBuilder{}.
    WithLogger(MakeLoggerFrom(config)).
    WithModel(config.modelPath).
    When(config.useCuda, &SessionBuilder::WithCUDAExecutionProvider, config.cudaOptions).
    When(config.useOpenVino, &SessionBuilder::WithOpenVINOExecutionProvider, config.openVinoOptions).
    WithOptimizationLevel(config.optimizationLevel).
    WithNumberOfIntraThreads(config.intraThreads).
    //...
    Build();

当然 rust这种代码也有很多

显然能想到

std::string output = std::to_string(address >> 24);
for (int i = 2; i >= 0; i--) {
  output.append(std::to_string((address >> (i * 8)) % 256) + ".");
}

使用to_chars

std::string output(4 * 3 + 3, '\0'); // allocate just one big string
char *point = output.data();
char *point_end = output.data() + output.size();
point = std::to_chars(point, point_end, uint8_t(address >> 24)).ptr;
for (int i = 2; i >= 0; i--) {
 *point++ = '.';
 point = std::to_chars(point, point_end, uint8_t(address >> (i * 8))).ptr;
}
output.resize(point - output.data());

干脆查表

char *to_chars_52(char *p, unsigned char x) {
  constexpr std::string_view table[256] = {
      "0",   "1",   "2",   "3",   "4",   "5",   "6",   "7",   "8",   "9",
      "10",  "11",  "12",  "13",  "14",  "15",  "16",  "17",  "18",  "19",
      "20",  "21",  "22",  "23",  "24",  "25",  "26",  "27",  "28",  "29",
      "30",  "31",  "32",  "33",  "34",  "35",  "36",  "37",  "38",  "39",
      "40",  "41",  "42",  "43",  "44",  "45",  "46",  "47",  "48",  "49",
      "50",  "51",  "52",  "53",  "54",  "55",  "56",  "57",  "58",  "59",
      "60",  "61",  "62",  "63",  "64",  "65",  "66",  "67",  "68",  "69",
      "70",  "71",  "72",  "73",  "74",  "75",  "76",  "77",  "78",  "79",
      "80",  "81",  "82",  "83",  "84",  "85",  "86",  "87",  "88",  "89",
      "90",  "91",  "92",  "93",  "94",  "95",  "96",  "97",  "98",  "99",
      "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
      "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
      "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
      "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
      "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
      "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
      "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
      "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
      "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
      "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
      "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
      "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
      "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
      "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
      "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
      "250", "251", "252", "253", "254", "255",
  };

  std::string_view sv = table[x];

  std::memcpy(p, sv.data(), sv.size());
  return p + sv.size();
}
// credit: Peter Dimov
std::string ipv52(const uint64_t address) noexcept {
  std::string output(4 * 3 + 3, '\0');
  char *p = output.data();

  p = to_chars_52(p, uint8_t(address >> 24));
  *p++ = '.';
  p = to_chars_52(p, uint8_t(address >> 16));
  *p++ = '.';
  p = to_chars_52(p, uint8_t(address >> 8));
  *p++ = '.';
  p = to_chars_52(p, uint8_t(address >> 0));

  output.resize(p - output.data());
  return output;
}

代码在这里

https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2023/02/01/str.cpp

CPU角度省内存技巧,使用上这些技巧,你的代码搞不好变慢,各种加fence。说实话,没看懂意图

介绍UBSan的方方面面使用

老文,但挺有意思。直接贴代码了。原理去原文看吧

// should be much more precise with large b
inline double fastPrecisePow(double a, double b) {
  // calculate approximation with fraction of the exponent
  int e = (int) b;
  union {
    double d;
    int x[2];
  } u = { a };
  u.x[1] = (int)((b - e) * (u.x[1] - 1072632447) + 1072632447);
  u.x[0] = 0;

  // exponentiation by squaring with the exponent's integer part
  // double r = u.d makes everything much slower, not sure why
  double r = 1.0;
  while (e) {
    if (e & 1) {
      r *= a;
    }
    a *= a;
    e >>= 1;
  }

  return r * u.d;
}
#include <iostream>

int main() {
    for (auto x : {"hello", "coding", "world"})
        std::cout << x << ", ";
}

等价于

#include <iostream>

int main()
{
  {
    const char *const __list21[3]{"hello", "coding", "world"};
    std::initializer_list<const char *> && __range1 
                            = std::initializer_list<const char *>{__list21, 3};
    const char *const * __begin1 = __range1.begin();
    const char *const * __end1 = __range1.end();
    for(; __begin1 != __end1; ++__begin1) {
      const char * x = *__begin1;
      std::operator<<(std::operator<<(std::cout, x), ", ");
    }
    
  }
  return 0;
}

std::initializer_list不能细想,越想越复杂

演示代码。说实话没怎么看懂

介绍 std::regular
看代码就懂了

template<class T>
concept movable = is_object_v<T> && move_constructible<T> &&
assignable_from<T&, T> && swappable<T>;

template<class T>
concept copyable = copy_constructible<T> && movable<T> && assignable_from<T&, const T&>;

template<class T>
concept semiregular = copyable<T> && default_constructible<T>;

template<class T>
concept regular = semiregular<T> &&...
Read more

C++ 中文周刊 第98期

28 Jan 14:56
1c09993
Compare
Choose a tag to compare

周刊项目地址

公众号

弄了个qq频道,手机qq点击进入

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

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

提交 issue

20230128 唉,不想上班


文章

还是介绍c++23特性,鉴于中文资料还是比较少的,这里推荐一下

之前咱们也讲过很多次别名引入导致的性能低下,编译期不能充分优化的问题。这里又科普一遍,还有谁不知道?

simd指令教学,感兴趣的可以看看

https://godbolt.org/z/PPsn4KM7Y

简单来说还是embed,借助embed实现concept reflexpr

讨论optional各种构造转换

  • c++20 编译期解析(compile-time parsing)以及实现类似rust macro rule

https://godbolt.org/z/zKbWc7MhE

https://godbolt.org/z/5ajjYs754

直接贴代码了。很复杂,值得研究一波

老文,讲了一些c++20的改进,比如constexpr

#include <iostream>
#include <variant>

constexpr std::variant<int, double> foo(int x) {
    std::variant<int, double> oi { x * 0.1 };
    if (x > 10)
        oi = x;
    return oi;
}

int main() {
   constexpr auto dv = foo(1);
   static_assert(std::holds_alternative<double>(dv));
   constexpr auto iv = foo(100);
   static_assert(std::holds_alternative<int>(iv));
}

再比如经典坑

std::variant<string, bool> x = "abc";   // 此时的x是bool,惊不惊喜

修订在这 https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r3.html

一些维护大项目的经验,比如ccache加速CICD,项目组织以及重用代码,甚至给了一个cmake模板 https://github.com/tfc/cmake_cpp_example

看着还不错


Raymond chen又发了一堆winrt的文章,我不了解,没细读,这里直接贴出来


对OI感兴趣的可以看看,有几个模板库 比如这个https://github.com/emthrm/cp-library

看个乐

感兴趣可以看看

温故知新

树的几种遍历,针对递归型,什么遍历,就在什么位置调用

如果是非递归用堆栈,前序遍历,那就堆栈里放left/right,后序遍历,那堆栈就放当前节点,中序遍历,那就先放left,放完了也就定好顺序了,访问节点和right就行了

我这里描述的非常模糊,边界条件也没说,不懂的话找个代码看看,我说个大概意思

在执行main之前还会执行别的动作。就是利用这个性质来打印。说实话一般

视频

就是基于cling的一个python内调用c++的工具。cling有句讲句活跃程度堪忧

>>> import cppyy
>>> cppyy.cppdef("""
... class MyClass {
... public:
...     MyClass(int i) : m_data(i) {}
...     virtual ~MyClass() {}
...     virtual int add_int(int i) { return m_data + i; }
...     int m_data;
... };""")
True
>>> from cppyy.gbl import MyClass
>>> m = MyClass(42)
>>> cppyy.cppdef("""
... void say_hello(MyClass* m) {
...     std::cout << "Hello, the number is: " << m->m_data << std::endl;
... }""")
True
>>> MyClass.say_hello = cppyy.gbl.say_hello
>>> m.say_hello()
Hello, the number is: 42
>>> m.m_data = 13
>>> m.say_hello()
Hello, the number is: 13
>>> class PyMyClass(MyClass):
...     def add_int(self, i):  # python side override (CPython only)
...         return self.m_data + 2*i
...
>>> cppyy.cppdef("int callback(MyClass* m, int i) { return m->add_int(i); }")
True
>>> cppyy.gbl.callback(m, 2)             # calls C++ add_int
15
>>> cppyy.gbl.callback(PyMyClass(1), 2)  # calls Python-side override
5

鉴于我们是c++周刊,python代码就不多列举了。大家感兴趣的自己玩玩

我没懂,这种和经典singleton有啥不一样吗,哦singleton全局的

gdb结合tui,结合python等等,没总结,感兴趣的可以看看

ppt在这里 https://www.jonathanmueller.dev/talk/meetingcpp2022/

作者在搞一个脚本语言虚拟机,对比switch,改成jumptable带来很大受益,讲的就是这个调优过程

话说回来,不看视频只看ppt的话 https://meetingcpp.com/mcpp/slides/?year=2022 这里有挺有有意思的

比如这个 https://meetingcpp.com/mcpp/slides/2022/Basic%20usage%20of%20PMRs%20for%20better%20performance8308.pdf

我觉得非常值得一看

我觉得还是直接看ppt吧,非常容易懂,我记得以前godbolt也讲过类似的主题

https://knatten.org/download/Anders%20Schau%20Knatten%20-%20Just%20Enough%20Assembly%20for%20Compiler%20Explorer%20-%20Meeting%20C++%202022.pdf

我贴一下代码

;--- 经典寄存器使用
mov rdi, 2
mov rsi, 4
add rdi, rsi
;结果 rdi 6, rsi 4

;--- 堆栈push/pop

mov rdi, 0xfedcba9876543210
push rdi
pop rsi

;结果 rsi=rdi=0xfedcba9876543210,经典赋值,两条指令,mov要多用一个寄存器/地址中转

;--- 访问地址

mov rsi, 0x3333333333333333
mov rdi, 0x2222222222222222
mov qword ptr [rsp - 8], rsi
add rdi, qword ptr [rsp - 8] 
;这里数组括号就是访问地址,把rsi弄到rsp-8的位置存一下,然后 add访问哪个地址的值,也就是rsi的值,加到rdi
; rdi 0x5555555555555555, rsi不变
; 为什么-8 因为rsi都是64位的寄存器
; byte: rax 8 eax 4 ax 2 al/ah 1

;来一个32位的例子

mov esi, 0x3333333333333333
mov edi, 0x2222222222222222
mov dword ptr [rsp - 8], esi
add edi, dword ptr [rsp - 8] 
;结果就不说了

;再来一个word例子

mov word ptr [rsp-8], 0x1111
mov word ptr [rsp-6], 0x2222
mov word ptr [rsp-4], 0x3333
mov word ptr [rsp-2], 0x4444
lea rdi, [rsp-8]              ; rdi指向rsp-8这个位置了
mov ax, word ptr [rdi+6]      ; ax 0x4444懂吧
mov rsi, 0
mov ax, word ptr [rdi+rsi*2]  ; 0x1111
inc rsi
mov ax, word ptr [rdi+rsi*2]  ; 0x2222

;---- 条件

 mov rsi, 2
 mov rdi, 3
 cmp rdi, rsi ;和j命令配合不满足继续走到jmp
 jg .greater
 mov rax, 0
 jmp .endif
.greater:
 mov rax, 1
.endif:

;---- 循环
; c代码这样
; int rax=0;
; for (int rcx=1;rcx!=3;++rcx) {rax += rcx;}

 mov rax, 0
 mov rcx, 1
.for
 cmp rcx, 3
 je .endfor
 add rax, rcx
 inc rcx
 jmp .for
.endfor

;---- 来个函数
;int sum(int a, int b){ return a + b;}

sum(int, int):
  push rbp
  mov rbp, rsp
  mov DWORD PTR [rbp-4], edi
  mov DWORD PTR [rbp-8], esi
  mov edx, DWORD PTR [rbp-4]
  mov eax, DWORD PTR [rbp-8]
  add eax, edx
  pop rbp
  ret
;能看懂吧,另外优化后肯定能看懂,省掉把入参传到栈上来回折腾的流程了
sum(int, int):
  lea eax, [rdi+rsi]
  ret

再来个例子,调用函数

;int times_two(int i);
;int sum_times_two(int a, int b){    return times_two(a + b);}
;int times_two(int i){    return i*2;}

sum_times_two(int, int):
  push rbp
  mov rbp, rsp
  sub rsp, 16
  mov DWORD PTR [rbp-4], edi
  mov DWORD PTR [rbp-8], esi
  mov edx, DWORD PTR [rbp-4]
  mov eax, DWORD PTR [rbp-8]
  add eax, edx
  mov edi, eax
  call times_two(int) ;看edi的用法
  leave
  ret
times_two(int):
  push rbp
  mov rbp, rsp
  mov DWORD PTR [rbp-4], edi
  mov eax, DWORD PTR [rbp-4]
  add eax, eax
  pop rbp
  ret

开源项目需要人手

  • asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
  • pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线

新项目介绍/版本更新

工作招聘

目前没看着有啥好工作,尽量别被开吧


看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持!

本文永久链接

如果有疑问评论最好在上面链接到评论区里评论,这样方便搜索,微信公众号有点封闭/知乎吞评论

C++ 中文周刊 第97期

19 Jan 06:30
3c8a502
Compare
Choose a tag to compare

周刊项目地址

弄了个qq频道,手机qq点击进入

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

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

提交 issue

祝大家新年快乐。

资讯

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

一月邮件列表

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/#mailing2023-01

编译器信息最新动态推荐关注hellogcc公众号 OSDT Weekly 2023-01-18 第185期

文章

笑死 #embed 早晚玩出花来

https://godbolt.org/z/Tj6c7jz1o

#include <string_view>
#include <array>

template <std::size_t N>
struct fixed_string final {
    constexpr explicit(true) fixed_string(const auto... cs) : data{cs...} {}

    constexpr explicit(false) fixed_string(const char (&str)[N + 1]) {
        std::copy_n(str, N + 1, std::data(data));
    }

    [[nodiscard]] constexpr auto operator<=>(const fixed_string&) const =
        default;

    [[nodiscard]] constexpr explicit(false) operator std::string_view() const {
        return {std::data(data), N};
    }

    [[nodiscard]] constexpr auto size() const -> std::size_t { return N; }

    std::array<char, N + 1> data{};
};

template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;
fixed_string(const auto... Cs) -> fixed_string<sizeof...(Cs)>;

template<fixed_string Name>
constexpr auto meta_contains = [] {
  static constexpr char self[] = { 
    #embed __FILE__ 
  };
  const auto code = std::string_view(std::data(self), std::size(self));
  const auto find = code.find(Name);
  return find != std::string_view::npos and code[find-1] != '\"';
}();

struct foo {};
struct bar {};

auto fn() -> void;

static_assert(not meta_contains<"struct x">);
static_assert(not meta_contains<"STD::string_view">);
static_assert(meta_contains<"std::string_view">);
static_assert(meta_contains<"struct foo">);
static_assert(meta_contains<"struct bar">);
static_assert(meta_contains<"auto fn()">);

再学点range

adjacent

std::vector v = { 1, 2, 3, 4, 5, 6, 7, 8 };
for (auto const& t : v | std::views::adjacent<3>) {
   std::cout << '[' << std::get<0>(t) << ',' 
                    << std::get<1>(t) << ',' 
                    << std::get<2>(t) 
             << ']' << '\n';
} 
/*
[1,2,3]
[2,3,4]
[3,4,5]
[4,5,6]
[5,6,7]
[6,7,8]
*/

//也可以这样

for (auto const& [a,b,c] : v | std::views::adjacent<3>) {
   std::cout << '[' << a << ',' << b << ',' << c << ']' << '\n';
}

slide和adjacent差不多,代码贴一下

auto print(R&& r) {
   std::cout << '[';
   bool first = true;
   for (auto const e : r) {
      if(first) first = false;
      else std::cout << ',';
       
      std::cout << e;
   }
   std::cout << ']' << '\n';
}
std::vector v = { 1, 2, 3, 4, 5, 6, 7, 8 };
for (auto const& c : v | std::views::slide(3)) {
   print(c);
}

/*
[1,2,3]
[2,3,4]
[3,4,5]
[4,5,6]
[5,6,7]
[6,7,8]
*/

chunk,分段

for (auto const& c : v | std::views::chunk(3)) {
   print(c);
}
/*
[1,2,3]
[4,5,6]
[7,8]
*/

chunk_by类似chunk,能提供一个谓词判断

bool differ_by_one(int const a, int const b)
{
    return std::abs(a - b) <= 1;
}
std::vector v = {1,1,2,3,2,2,1,3,4,8,7,6,7};
for (auto const& c : v | std::views::chunk_by(differ_by_one))
{
   print(c);
}
/* 按照相邻差1来分段 
[1,1,2,3,2,2,1]
[3,4]
[8,7,6,7]
*/

再来个例子

bool same_kind(char const a, char const b)
{
    bool b1 = std::isdigit(a);
    bool b2 = std::isdigit(b);
    return (b1 && b2) || (!b1 && !b2);
}
std::string s {"1234abc56e789fghi"};
for (auto const& c : s | std::views::chunk_by(same_kind))
{
   print(c);
}
/*
按照字母类型来分段

[1,2,3,4]
[a,b,c]
[5,6]
[e]
[7,8,9]
[f,g,h,i]

*/
#include <iostream>
class MyDistance{
 public:
    explicit MyDistance(double i):m(i){}
    friend MyDistance operator +(const MyDistance& a, const MyDistance& b){         // (1)
        return MyDistance(a.m + b.m);
    } 
    friend MyDistance operator -(const MyDistance& a, const MyDistance& b){         // (2)
        return MyDistance(a.m - b.m);
    }
    friend std::ostream& operator<< (std::ostream &out, const MyDistance& myDist){  // (3)
        out << myDist.m << " m";
        return out;
    }  
 private:
    double m;
};

int main() {
    std::cout << "MyDistance(5.5) + MyDistance(5.5): " << MyDistance(5.5) + MyDistance(5.5) << '\n';  // (4)
    std::cout << "MyDistance(5.5) - MyDistance(5.5): " << MyDistance(5.5) - MyDistance(5.5) << '\n';  // (5)
}

没啥说的,没有friend就找不到这几个operator函数,而且这么写也不用非得是成员函数

好像之前说过这个?反复强调,undefined behavior未定义行为不等于实现定义,有可能是历史遗留问题,也有可能就毁灭地球

逆天用法

std::vector<unsigned char> getFavicon() {
  return {
    #embed "favicon.ico"
  };
}
这种场景embed可能退化成initializer_list,复制到栈上,然后再复制到vector,堆上,白白浪费

`#embed`就老老实实当属性二进制用,这种写法也不是不行,字符串不大也可以

作者写了个提案,方便解决这种情况。具体没看,大概就是识别优化掉这玩意

看段代码

#include <array>

struct Node {
    int a = 1, b = 1;
};

std::array <Node, 10'000> a;

int main() {}

问题在于array占用80k额外空间,加上Node初始化占用多余的空间,怎么样能省?初始化可以用0,省掉,本身全局变量并没有很好的办法优化掉

视频

介绍静态分析工具 https://github.com/secure-software-engineering/phasar

看不懂

代码在这里 https://github.com/sslotin/amh-code

他也是咱们之前提到过很多次的这个博客 https://en.algorithmica.org/hpc/ 的作者。

这个讲的就是这个博客的内容,如何优化binary search,简单来说是SIMD,说实话SIMD我不太懂。没怎么看,不过我觉得是值得一看的

这里的aliasing表述的是多个指针使用指向同一个对象的情况,比如滥用引用,比如自己给自己赋值,之前也提到过误用引用导致错误而引入decay_copy以及c++23的auto,本质上这种问题还是指针的歧义,导致编译器保守了,没有彻底优化

来个代码

void byRef(std::vector<double>& v, const double& coeff) {
  for (auto& i : v) i *= std::sin(coeff);
}

void byVal(std::vector<double>& v, double coeff) {
  for (auto& i : v) i *= std::sin(coeff);
}

注意coeff这种没有必要的const&

再比如

using namespace std;
using namespace std::literals;
template <typename Fun>
void test(string_view name, Fun F) {
    char buffer[50] = "hello ";
    F(buffer + 1, buffer, 6);
    buffer[0] = ' ';
    cout << name << " [" << buffer << "] "
         << (" hello "sv == buffer ? "Good\n" : "Bad\n");
}

void loopcpy(char* dst, const char* src, int size) {
    while (size--) *dst++ = *src++;
}
int main() {
    test("NOP    ", [](auto...) {});
    test("loopcpy", loopcpy);
    test("strcpy ", [](auto dst, auto src, auto...) { strcpy(dst, src); });
    test("strncpy ", strncpy);
    test("memcpy ", memcpy);
    test("memmove", memmove);
    test("copy_n ",
         [](auto dst, auto src, auto size) { copy_n(src, size, dst); });
    return 0;
}

loopcpy这种明显无法区分src dst相同的副作用

在比如

using namespace std;
using namespace std::literals;


int main() {
//    members();
    complex<int> x{2, 2};
    x *= reinterpret_cast<int*>(&x)[0];  // multiply by real part
    cout << "expect (4,4) and get " << x << "\n";
//    lambdas();
    auto add_to_all = [](auto& v, const auto& suffix) {
        for_each(begin(v), end(v), [&](auto& x) { x += suffix; });
    };
    vector<int> v{1, 2, 3};
    add_to_all(v, v[0]);
    cout << "expected [2,3,4] and got [" << v[0] << "," << v[1] << "," << v[2]
         << "]\n";
    return 0;
}

自己改自己以及滥用引用

再比如

int main() {
    auto minmax = [](const string& i, const string& j, string* out_min,
                     string* out_max) {
        *out_min = min(i, j);
        *out_max = max(i, j);
    };
    array<string, 2> arr{"22222", "11111"};
    // try to sort
    minmax(arr[0], arr[1], &arr[0], &arr[1]);
    cout << "expect 22222 and get " << arr[1] << "\n";
    auto concat = [](string& result, const auto&... args) {
        ((result += args), ...);
    };
    string x{"hello "}, y{"world "};
    concat(x, y, x);
    cout << "expect [hello world hello ] and get [" << x << "]\n";
    return 0;
}

这种问题c就有,union都有,但c有__restrict__ c++没有。那么怎么从代码角度避免这种问题?

传值,引用用std::ref,强类型区分

开源项目需要人手

  • asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
  • pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线

新项目介绍/版本更新

Read more

C++ 中文周刊 第96期

13 Jan 14:39
140b919
Compare
Choose a tag to compare

周刊项目地址

公众号

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

弄了个qq频道,手机qq点击进入

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

提交 issue

0113

部门聚餐了延误了一下。本周没看视频


资讯

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

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

一个博客收集网站 https://swedencpp.se/blogs 英文c++的最新博客收集

文章

取对数

哎。倒腾cmake我头疼

有点意思。这种针对牛逼网卡的优化我感觉大厂都在做类似的玩意

又一个c++项目引入rust的。之前有火狐浏览器,clickhouse, redpanda,linux内核,唱衰一波,不过不要慌,c++程序员一时半会不会失业

看代码

constexpr auto get = [](auto value) {
  if consteval {
    return value;
  } else {
    auto result = 0;
    asm("movl $42, %%eax\n" : "=r" (result) );
    return result;
  }
};

static_assert(0 == get(0));
static_assert(4 == get(4));
static_assert(2 == get(2));

consteval auto fn() {
    return get(0);
}

int main(int argc, char**) {
  assert(42 == get(0));
  assert(42 == get(argc));
  return fn();
}

希望大家身体健康,活得久一点,就能用到静态反射了

编译器标准库用到很多变量是两个下划线 下划线大写字母开头的。自己定义变量尽量别用

测了一下simdutdf在Zen4的表现,挺强的

blake3是不是就是simd加速的?

给oilshell设计的GC。没仔细看

optional做函数参数是十分不恰当的。这玩意只适合做返回值

QVarLengthArray类似vector,区别在于对小数据做SBO优化,且resize不会做额外的初始化动作。初始化动作是c++默认有的。很多场景来看是多余的,比如string。c++20/23做了许多修正

比如

std::unique_ptr<int[]> p3 = std::make_unique_for_overwrite<int[]>(100'000);

再比如string

// C++23
std::string s = ~~~;
 
auto oldSize = s.size();
 
s.resize_and_overwrite(100'000, [oldSize](char *buf, std::size_t count) {
 
  // For starters, s will *reserve* enough space, without initializing it.
  //
  // - buf points to the string's storage (i.e. s.data()) *after* the reserve;
  // - count is the 1st argument to resize_and_overwrite (100k), so
  //   we can re-use this function with different `count`s.
 
 
  // Populate the range [buf, buf+count]. We can mutate the entirety of
  // the string's buffer. But let's say we're just interested in populating
  // the new contents -- from position oldSize up to count.
  for (size_it i = oldSize; i < count; ++i)
    buf[i] = generateData(i);
 
  // Notes:
  // - If we're growing, the newly created storage is *uninitialized*.
  //   Don't read from it!
  //
  // - The old contents are still there, and we can access them freely.
  //   If needed, carry `oldSize` manually, to identify where to start 
  //   writing (and leave the old contents alone).
  //
  // - It is legal to write into buf[count],
  //   but it will be overwritten with \0 when we're done.
     
  // We don't need to populate the *entire* buffer -- we may stop short!
  // The returned value will be the new size of the string.
 
  return actual_new_size;
});

QVarLengthArray不会做多余的初始化,请注意(不过QT这套东西会玩的越来越少了,大部分读者应该不玩QT)

基础知识,不会的可以去看《程序员的自我修养 链接/库》这本书

MSVC有两套coroutine API

// in <experimental/coroutine>
#ifndef _ALLOW_COROUTINE_ABI_MISMATCH
#pragma detect_mismatch("_COROUTINE_ABI", "1")
#endif // _ALLOW_COROUTINE_ABI_MISMATCH

// in <coroutine>
#ifndef _ALLOW_COROUTINE_ABI_MISMATCH
#pragma detect_mismatch("_COROUTINE_ABI", "2")
#endif // _ALLOW_COROUTINE_ABI_MISMATCH

使用 /std:c++20/std:c++latest,才会用最新的api,experimental是c++17旧的

又是Windows API,如何处理flags,我直接贴下面,不懂windows

Flag Meaning Recommendation
DISCONNECTED No network interface detects any network Treat as offline.
NOTRAFFIC An interface is connected, but it cannot send or receive network traffic. Treat as offline.
SUBNET/LOCALNETWORK An interface has been configured to send traffic, but the system cannot confirm Internet connectivity. Make one attempt to contact service.
INTERNET The system has confirmed access to Microsoft Internet sites. Treat as fully online.

没看懂

视频

没啥说的,之前讲过,#embed可以嵌入二进制,比如插个音乐,文本等等

开源项目需要人手

  • asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
  • pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线

新项目介绍/版本更新

没看懂这玩意是干什么的


看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持!

本文永久链接

如果有疑问评论最好在上面链接到评论区里评论,这样方便搜索,微信公众号有点封闭/知乎吞评论

C++ 中文周刊 第95期

06 Jan 13:07
7faaece
Compare
Choose a tag to compare

周刊项目地址

公众号

弄了个qq频道,手机qq点击进入

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

提交 issue

新年第一周


文章

__builtin_clzll.作者还讲了一些优化的东西,涨涨见识

总结了2022年来c++的各种进展,很全面了

直接看代码

constexpr auto foo() {
  static constexpr auto value = 42; // error in C++20, okay in C++23
  return value;
}

乍看没啥用

给个例子

template<char... Cs>
[[nodiscard]] constexpr auto to_string_view(){
    static constexpr char p[sizeof...(Cs)] = {Cs...};
    return std::string_view(p, sizeof...(Cs));
}

我发现这个特性和例子差距有点像你已经学会1+1=2了来证明黎曼猜想吧那种感觉

实现条件判断版本的none of any of

auto none_of(auto pred, auto... ts) {
    const auto a = std::array{ts...};
    return std::none_of(std::cbegin(a), std::cend(a), pred);
}

auto before(int a, int b, int c) {
    if (a != 2 and b != 2 and c != 2) {
      return 42;
    }
    return 0;
}

auto after(int a, int b, int c) {
    if (none_of([](auto x) { return x == 2; }, a, b, c)) {
      return 42;
    }
    return 0;
}

anyof怎么实现?

#include <utility>
#include <tuple>
#include <concepts>

template<class ... Args>
struct Comp {
    template<class T>
    auto operator==(T && other) {
        return std::apply(
            [&other](auto &&... data) {
                return (((std::equality_comparable_with<decltype(data), T>) && data == other) || ...);
            },
            this -> data
        );
    }
    std::tuple<Args...> data {};
};

template<class ...Args>
auto any_of(Args && ... args)  {
    return Comp<Args...> {
        std::make_tuple(std::forward<Args>(args)...)
    };
    
}

和上面差距有点大

实现了一个gcc插件支持[[invariant]]特性,代码在这里https://github.com/GavinRay97/gcc-invariant-plugin

博客记录了开发插件的方法和过程,挺有意思的

gdb调试和shell交互,复杂

介绍他的折腾

就是std::execution::par/std::execution::par_unseq这玩意

std::vector<size_t> indices(num_pixels);
 // initialize indices with 0, 1, ..
std::iota(indices.begin(), indices.end(), 0); // needs <numeric>

std::transform( // needs <algorithm>
    std::execution::par, // <-- needs <execution>
    indices.begin(), indices.end(), pixels.begin(), 
    [](size_t index){
        return expensive_calculation(index);
    }
);

老生常谈讲智能指针那套东西

检查有没有std::hash特化

struct HasStdHash {
private:
  template <class T, class Dummy = decltype(std::hash<T>{})>
  static constexpr bool exists(int) {
    return true;
  }

  template <class T>
  static constexpr bool exists(char) {
    return false;
  }

public:
  template <class T>
  static constexpr bool check() {
    return exists<T>(42);
  }
};

std::cout << "Does std::string have std::hash? " << HasStdHash::check<std::string>();

能不能更泛化一点?

template <template <class... InnerArgs> class Tmpl>
struct IsSpecialized {
private:
  template <class... Args,
          class dummy = decltype(Tmpl<Args...>{}.~Tmpl<Args...>())>
  static constexpr bool exists(int) {
    return true;
  }

  template <class... Args>
  static constexpr bool exists(char) {
    return false;
  }

public:
  template <class... Args>
  static constexpr bool check() {
    return exists<Args...>(42);
  }
};

但这个代码对于这种场景是无效的

template<class T> struct SomeStruct;
bool test1 = IsSpecialized<SomeStruct>::check<std::string>();

template<> struct SomeStruct<std::string> {};
bool test2 = IsSpecialized<SomeStruct>::check<std::string>();

后面又讨论了一通ADL检测,我已经看不懂了

随便看看

cuda代码调优记录。看不懂

模拟器里玩模拟器,看不懂

msvc一个bug

#include <iostream>
#include <string>

template <typename T>
T galactus_the_devourer_of_const(const T& v) {
    return false ? std::move(T{}) : std::move(v);
}

int main() {
    const std::string food = "asdf";
    std::cout << "before: " << food << '\n';
    galactus_the_devourer_of_const(food);
    std::cout << "after:  " << food << '\n';
    return 0;
}

// before: asdf
// after:  

莫名其妙的被move了。解决办法,/permissive-,默认是/permissive

感兴趣可以看看

介绍这个库 https://github.com/iboB/xmem

可以分析智能指针引用,用法就不贴了。和hook malloc那种类似。不过要做很多很多适配代码

看代码

namespace winrt::Contoso::implementation {
    struct ItemCollection : ItemCollectionT<ItemCollection>{
        template<typename...Args> auto First(Args&&... args) {
            return m_items.First(args...);
        }

        template<typename...Args> auto GetAt(Args&&... args) {
            return m_items.GetAt(args...);
        }

        template<typename...Args> auto Size(Args&&... args) {
            return m_items.Size(args...);
        }

        template<typename...Args> auto IndexOf(Args&&... args) {
            return m_items.IndexOf(args...);
        }

        template<typename...Args> auto GetMany(Args&&... args) {
            return m_items.GetMany(args...);
        }
        // And our bonus method
        hstring ToJson();
    private:
        Windows::Foundation::Collections::IVector<Contoso::Item> m_items;
    };
}

视频

optvier做高频交易的,这个talk还是很有东西的

一些性能优化点

小对象尽可能紧凑,利用好cpu cache

能用vector用vector,甚至boost::stable_vector,unordered_map开销非常恐怖 workding set size有分析工具wss https://github.com/brendangregg/wss

seqlock怎么做更快?

作者实现了个基于奇偶版本号的lock,单生产者多消费者,T很小,这种写法没啥竞争,很值

template<typename T>
class SeqLock {
  T mData;
  std::atomic<uint32_t> mVersion;
};

template<typename T>
void SeqLock<T>::Store(const T& value) {
  mVersion+=1;
  std::memcpy(&mData, value, sizeof(T));
  mVersion+=1;
}

template<typename T>
bool SeqLock<T>::Load(T& value) {
  const auto version = mVersion.load();
  if (version & 1 != 0) {
      return false;
  }
  std::memcpy(&value, mData, sizeof(T));
  return version == mVersion;
}

更快的SPMC?

考虑消费队列 SPSC

struct SPSCQueue {
  alignas(64) std::atomic<uint64_t> mWriteIndex;
  alignas(64) std::atomic<uint64_t> mReadIndex;
  alignas(64) uint8_t mData[0];
};

就是一个循环buffer

SPMC那就不用维护mReadIndex,同时尽可能的让竞争更小

struct SPMCQueueV1 {
  alignas(64) std::atomic<uint64_t> mIndex;
  alignas(64) std::atomic<uint64_t> mPendingIndex;
  alignas(64) uint8_t mData[0];
};
template <typename C>
void SPMCQueueV1::Push(MessageSize size, C WriteCallback) {
    mPendingIndex += size;
    std::memcpy(mCurrent, size, sizeof(MessageSize));
    WriteCallback(mCurrent +  sizeof(MessageSize));
    mIndex += size;
}

template <typename C>
void SPMCQueueV1::Pop(C ReadCallback) {
    if (mPendingIndex == mIndex) return;
    MessageSize size;
    std::memcpy(&size, mCurrent + sizeof(MessageSize), sizeof(MessageSize));
    uint8_t buffer[size];
    std::memcpy(buffer, mCurrent + sizeof(MessageSize), size);
    ReadCallback(buffer, mSize);
}

性能不行

考虑seqlock的思路,使用版本号来替换index,降低index频繁修改的开销,均摊到每个槽的版本号上,性能直接起飞

每个槽都有mBlockCounter和mVersion,mVersion判定变化,mBlockCounter控制消费

struct Block {
  alignas(64) std::atomic<uint64_t> mVersion;
  alignas(64) std::atomic<uint64_t> mSize;
  alignas(64) uint8_t mData[0];
};
struct Header {
  alignas(64) std::atomic<uint64_t> mBlockCounter;
  alignas(64) Block mData[0];
};

template <typename C>
void SPMCQueueV2::Push(MessageSize size, C WriteCallback) {
    mVersion+=1
    WriteCallback(&mCurrentBlock->mData[0]);
    mVersion+=1
    mBlockCounter+=1
}

<img src="h...

Read more

C++ 中文周刊 第94期

30 Dec 12:08
db61cb4
Compare
Choose a tag to compare

周刊项目地址

公众号

弄了个qq频道,手机qq点击进入

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

提交 issue

马上2022就要结束了。祝大家新年快乐。

我感觉这波阳性我算比较早期的。希望大家都没事。


文章

值类型重申,可能很多人还停留在modern effective c++介绍的auto那里

考虑一种需求,把二进制编成ascii码, base64有点复杂,不如base16

void encode_scalar(const uint8_t *source, size_t len, char *target) {
  const uint16_t table[] = {
      0x3030, 0x3130, 0x3230, 0x3330, 0x3430, ...
      0x6366, 0x6466, 0x6566, 0x6666};
  for (size_t i = 0; i < len; i++) {
    uint16_t code = table[source[i]];
    ::memcpy(target, &code, 2);
    target += 2;
  }
}

显然,能simd

 __m128i shuf = _mm_set_epi8('f', 'e', 'd', 'c', 'b', 'a', '9', '8', '7', '6',
                              '5', '4', '3', '2', '1', '0');
  size_t i = 0;
  __m128i maskf = _mm_set1_epi8(0xf);
  for (; i + 16 <= len; i += 16) {
    __m128i input = _mm_loadu_si128((const __m128i *)(source + i));
    __m128i inputbase = _mm_and_si128(maskf, input);
    __m128i inputs4 =
        _mm_and_si128(maskf, _mm_srli_epi16(input, 4));
    __m128i firstpart = _mm_unpacklo_epi8(inputs4, inputbase);
    __m128i output1 = _mm_shuffle_epi8(shuf, firstpart);
    __m128i secondpart = _mm_unpackhi_epi8(inputs4, inputbase);
    __m128i output2 = _mm_shuffle_epi8(shuf, secondpart);
    _mm_storeu_si128((__m128i *)(target), output1);
    target += 16;
    _mm_storeu_si128((__m128i *)(target), output2);
    target += 16;
  }

代码就不列出来了,在这里 https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2022/12/23/base16.cpp

直接看性能吧

方法 速度
table lookup 0.9 GB/s
128-bit vectors 6.4 GB/s
256-bit vectors 11 GB/s

常规

static const std::unordered_set<std::string_view> special_set = {
    "ftp", "file", "http", "https", "ws", "wss"};

bool hash_is_special(std::string_view input) {
  return special_set.find(input) != special_set.end();
}

枚举

bool direct_is_special(std::string_view input) {
  return (input == "https") | (input == "http") | (input == "ftp") |
         (input == "file") | (input == "ws") | (input == "wss");
}

既然是这种特殊短字符串,直接转成int给大家开开眼

static inline uint64_t string_to_uint64(std::string_view view) {
  uint64_t val;
  std::memcpy(&val, view.data(), sizeof(uint64_t));
  return val;
}

uint32_t string_to_uint32(const char *data) {
  uint32_t val;
  std::memcpy(&val, data, sizeof(uint32_t));
  return val;
}


bool fast_is_special(std::string_view input) {
  uint64_t inputu = string_to_uint64(input);
  if ((inputu & 0xffffffffff) == string_to_uint64("https\0\0\0")) {
    return input.size() == 5;
  }
  if ((inputu & 0xffffffff) == string_to_uint64("http\0\0\0\0")) {
    return input.size() == 4;
  }
  if (uint32_t(inputu) == string_to_uint32("file")) {
    return input.size() == 4;
  }
  if ((inputu & 0xffffff) == string_to_uint32("ftp\0")) {
    return input.size() == 3;
  }
  if ((inputu & 0xffffff) == string_to_uint32("wss\0")) {
    return input.size() == 3;
  }
  if ((inputu & 0xffff) == string_to_uint32("ws\0\0")) {
    return input.size() == 2;
  }
  return false;
}

直接看看速度

GCC 11 Intel Ice Lake

方法 速度
std::unordered_map 20 ns/string
direct 9.1 ns/string
fast 3.0 ns/string

Apple M2 LLVM 12

方法 速度
std::unordered_map 14 ns/string
direct 5.5 ns/string
fast 1.6 ns/string

硬转效果还挺好

看代码

struct person {
    int age;
    std::string name;
}

// ...

auto alice = std::make_shared<person>("Alice", 38);


std::shared_ptr<std::string> name(alice, &alice->name);
assert(alice.use_count() == name.use_count()); // single-threaded use only

通过第二种构造,name相当于alice的别名了,这么写问题出在哪里?

alice 可能被乱搞,可能已经失效了,这个时候使用alice的name是有问题的

直接来个极端的例子

std::shared_ptr<void> null;
std::shared_ptr<std::string> weirdo(null, &some_global_string_that_is_always_valid)

null是无效的但weirdo是有效的。https://godbolt.org/z/xT5qzK443

不要用shared_ptr的这种构造函数。很容易写出坑

数据复制是最常见的场景了,把数据传来传去,所以说一个memcpy速度快是很重要的。

那么实现一个快速的memcpy要考虑什么呢?

  • Fail: Copy-in-RAM and DMA engines
  • Both the CPU side and the memory side of caches matter
  • Load/Store Partial and Double-width-shift help significantly
  • Longer Prefetching matters
  • Letting the memory controller know about prefetch length can be 3x faster
  • Controlling cache pollution matters
  • Fixed-precision formatting of floating-point numbers

感觉很牛逼。浮点数啥的我一直不懂

介绍c++23新特性。不多说了。说了好多次了

template<auto... Ns> consteval auto fn() {
  std::vector v{Ns...};
  return std::size(v);
}

static_assert(3uz == fn<1, 2, 3>());

额,怎么说呢这段代码,想不出有啥用途

性能路径尽量别用异常,懂得都懂。不多说了

能快一点,但这玩意一般不是瓶颈

size_t sve_strlen(const char *s) {
  /*if(svcntb() > 256) {
    // do something here because we assume that our
    // vectors have no more than 256.
  }*/
  size_t len = 0;
  while (true) {
    svuint8_t input = svldff1_u8(svptrue_b8(), (const uint8_t *)s + len);
    svbool_t matches = svcmpeq_n_u8(svptrue_b8(), input, 0);
    if (svptest_any(svptrue_b8(), matches)) {
      return len + svlastb_u8(svbrka_z(matches, matches), svindex_u8(0, 1));
    }
    len += svcntb();
  }
}

都是一坨难受的代码

timer内部标记一个flag,然后外面UI事件框架根据flag来搞优先级?

没有嗷别做梦了

手把手教你cmake嵌入复杂文件信息,tar包

值得一看

视频

cppcon

讲struc_pack的。和boost.pfr差不多

开源项目需要人手

  • asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
  • pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线

新项目介绍/版本更新

  • saf asio基础上的scheduler
  • libenvpp A modern C++ library for type-safe environment variable parsing
  • xmake.sh xmake脚本

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持!

本文永久链接

C++ 中文周刊 第93期

21 Dec 14:51
be6710e
Compare
Choose a tag to compare

周刊项目地址

公众号

弄了个qq频道,手机qq点击进入

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

提交 issue


资讯

编译器信息最新动态推荐关注hellogcc公众号 2022-12-14 第180期

文章

struct unpacked {
  char a;  // size: 1b => size: 4b
  int  b;  // size: 4b => size: 4b
  char c;  // size: 1b => size: 4b
           //             ---------
           //             size: 12b
};

struct packed {
  char a;  // size: 1b => size: 4b
  char b;  // size: 1b => size: 4b
  int  c;  // size: 4b => size: 8b
           //             --------
           //             size: 8b
};

static_assert(12 == sizeof(unpacked));
static_assert(8 == sizeof(packed));

struct simple {
  int a;   // size: 4b => align: 4b
};

struct empty {
           // size: 1b => align: 1b
};

这个我感觉都知道,问题是,如何检测是否对齐呢?

template<auto Id>
struct alignment {
  std::size_t* alignments{};
  template<class T> constexpr operator T() const {
    alignments[Id] = alignof(T);
    return {};
  }
};

template<class T, class... TArgs>
using AggregateInitializable = decltype(T{std::declval<TArgs>()...});

template<class T, auto... Ns>
constexpr auto is_packed_layout(std::index_sequence<Ns...>) {
  if constexpr(std::experimental::is_detected_v<AggregateInitializable, T, alignment<Ns>...>) {
    std::size_t alignments[sizeof...(Ns)]{};
    void(T{alignment<Ns>{alignments}...});
    return (alignments[Ns] <= ... <= sizeof(T));
  } else {
    return is_packed_layout<T>(std::make_index_sequence<sizeof...(Ns) - 1>{});
  }
}

template<class T, class = std::enable_if_t<std::is_aggregate_v<T>>>
constexpr std::bool_constant<is_packed_layout<T>(
  std::make_index_sequence<sizeof(T)>{})> is_packed_layout_v{};

static_assert(12 == sizeof(unpacked));
static_assert(not is_packed_layout_v<unpacked>);

static_assert(8 == sizeof(packed));
static_assert(is_packed_layout_v<packed>);

static_assert(1 == sizeof(empty));
static_assert(is_packed_layout_v<empty>);

static_assert(4 == sizeof(simple));
static_assert(is_packed_layout_v<simple>);

学习一波

值得一看

很精彩的抓bug,值得一看

很详尽的记录了c23变了啥

整了个脚本把moc开头的生成的头文件include一下

老生常谈了属于是,列表初始化这个玩意

一个cmake教程

直接看代码

auto [_, was_inserted] =
      done_events_.insert({device_ordinal, std::move(done_event)});



auto [installer_download_url, installer_filename] = extract_installer_asset_download_info(release_object);
co_return new_version_download_info{ extract_release_page_url(release_object),
                                                 std::move(github_version),
                                                 std::move(installer_download_url),
                                                 std::move(installer_filename) };



const auto [colorForeground, colorBackground] = renderSettings.GetAttributeColors(textAttributes);



const auto [first_nonmatching, error_condition] 
    = std::from_chars(val.data(), val.data() + val.size(), result);

其实就可以当作多个返回值解包来用

简单题,以下四段代码会不会inline?

A

inline int fn(int v) { return v; }
int main(int argc, char *argv[]) { return fn(0); }

B

//remove inline
int fn(int v) { return v; }
int main(int argc, char *argv[]) { return fn(0); }

C

//move function body
int fn(int v);
int main(int argc, char *argv[]) { return fn(0); }
int fn(int v) { return v; }

D

//extern C and non zero param
extern "C" int fn(int v);
int main(int argc, char *argv[]) { return fn(123); }
int fn(int v) { return v*0; }

答案是全都会inline, gcc/clang无差别。这是简单题。继续,
下面几段代码,头文件分开,代码是

#include "header.h"
int main(int argc, char *argv[]) { return fn(123); }

他们会不会inline?

A:

//Using a header without inline keyword
int fn(int v) { return v*0; }

B:

//using noinline
__attribute__ ((noinline))
int fn(int v) { return v*0; }

C:

//add the inline keyword
__attribute__ ((noinline))
__inline int fn(int v) { return v*0; }

D:

//Using both noinline and always_inline
__attribute__ ((noinline))
__attribute__((always_inline))
__inline int fn(int v) { return v*0; }

E:

//Same but swap
__attribute__((always_inline))
__attribute__ ((noinline))
__inline int fn(int v) { return v*0; }

有点复杂了

A clang/gcc都inline,

B clang会忽视这个noinline设置,直接inline,gcc不会

C 都不inline,因为指定了__inline又修饰成noinline,编译器准确翻译

D 都不inline,gcc会告警两个修饰词冲突

E 都inline gcc会告警两个修饰词冲突

DE都是修饰符出现的早说了算。另外CD如果去掉__inline那就都会inline了,得有inline,修饰才有作用

上强度了是吧?再来!

A:

#include <stdlib.h>
int main(int argc, char *argv[]) { return atoi("0"); }

B:

//using strtol
#include <stdlib.h>
int main(int argc, char *argv[]) { return strtol("0", 0, 10); }

C:

//using strtod which returns a double
#include <stdlib.h>
int main(int argc, char *argv[]) { return strtod("0", 0); }

谁会内联?这个涉及到这几个库接口的实现在那一层以及实现形式

atoi clang就能内联,而gcc是通过strtol来实现的

换个口味!库实现谁知道啊!下一题!

A:

#include <vector>
int main(int argc, char *argv[]) { std::vector<int> v; v.push_back(1000); return 0; }

B:

//Added an if
#include <vector>
int main(int argc, char *argv[]) { std::vector<int> v; v.push_back(1000); if (v.size() > 0) { return 0; } return 1; }

C:

//Added a pop inside the if and returned the size
#include <vector>
int main(int argc, char *argv[]) { std::vector<int> v; v.push_back(1000); if (v.size() > 0) { v.pop_back(); return v.size(); } return 1; }

会不会内联?
clang能完全优化掉,gcc不能 (O2)。原因没深究。clang收益有点明显了,来点复杂的!

A:

class B { public: virtual int test() { return 0; }};
class D : public B { public: int test() override { return 1; }};
int main(int argc, char *argv[]) {
    D d;
    B*b = &d;
    auto p = dynamic_cast<D*>(b);
    return !p;
}

B:

//Add final to D
class B { public: virtual int test() { return 0; }};
class D final : public B { public: int test() override { return 1; }};
int main(int argc, char *argv[]) {
	D d;
	B*b = &d;
	auto p = dynamic_cast<D*>(b);
	return !p;
}

C:

//Both branches are 0
class B { public: virtual int test() { return 0; }};
class D final : public B { public: int test() override { return 1; }};
int main(int argc, char *argv[]) {
	D d;
	B*b = &d;
	auto p = dynamic_cast<D*>(b);
	if (p)
		return 0;
	return 0;
}

D:

//replace the first return
class B { public: virtual int test() { return 0; }};
class D final : public B { public: int test() override { return 1; }};
int main(int argc, char *argv[]) {
	D d;
	B*b = &d;
	auto p = dynamic_cast<D*>(b);
	if (p)
		return ((D*)p)->test()-1;
	return 0;
}

E:

//What happens if you change the cast to reinterpret_cast
class B { public: virtual int test() { return 0; }};
class D final : public B { public: int test() override { return 1; }};
int main(int argc, char *argv[]) {
	D d;
	B*b = &d;
	auto p = reinterpret_cast<D*>(b);
	if (p)
		return ((D*)p)->test()-1;
	return 0;
}

AB都内联不了。CD gcc能内联,E都能内联

已经有点折磨了,有啥差别?为啥E可以AB就不行?差别在哪里?为啥CD和AB差不多,但能内联?(坑爹的cast)

最后一轮!
A:

//main.cpp
inline int getzero();
int main(int argc, char *argv[]) { return getzero(); }

//getzero.cpp
int getzero() { return 0; }

B:

//A again but add in -flto

C:

//Use -flto
#include <stdlib.h>
int main(int argc, char *argv[]) { return strtol("0", 0, 10); }

D:

//For a laugh, recursive fibonacci
int fibonacci(int n) {
	if(n == 0)
		return 0;
	else if(n == 1)
		return 1;
	else {
		return (fibonacci(n-1) + fibonacci(n-2));
	}
}
int main() { return fibonacci(0); }

A 不内联,会告警,B会内联,LTO发威,C即使LTO gcc也不内联,这是和实现有关的。clang可以,D是搞笑的就不说了

博士实现了一个strstr avx版本,代码在这里 https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2022/12/15/check.cpp

介绍c++23的属性,assume,这玩意是__builtin_assume

`void limiter(float* data, size_t size) {
    [[assume(size > 0)]];
    [[assume(size % 32 == 0)]];
    
    for (size_t i = 0; i < size; ++i) {
        [[assume(std::isfinite(data[i])]];
        data[i] = std::clamp(data[i], -1.0f, 1.0f);
    }
}

直...

Read more