Skip to content

Releases: wanghenshui/cppweeklynews

C++ 中文周刊 第86期

28 Oct 11:55
2159b8b
Compare
Choose a tag to compare

C++ 中文周刊 第86期

reddit/hackernews/lobsters/meetingcpp/purecpp/知乎/等等摘抄一些c++动态

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

公众号也有了

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

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

可以贴在下一期草稿里 草稿链接

2022 10 29


资讯

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

编译器信息最新动态推荐关注hellogcc公众号 2022-10-26 第173期

2022 purecpp大会ppt和视频

http://www.purecpp.cn/detail?id=2322

文章

介绍MSVC在copy elision move elision 的改进

consteval auto to_number(auto str) {
    int value;{} 
    std::from_chars(std::cbegin(str), std::cend(str), value);
    return value;
}
static_assert(42 == to_number(std::string_view{"42"}));

调试工具。老生常谈了

简单说,这个就是sqlite里的printf遇到%Q %q %w且字符串 非常非常非常大,才会触发这个CVE。且sqlite本身不会触发

sqlite不是100%分支覆盖么,为啥还有问题?分支覆盖了并不代表没问题。fuzzer也有可能覆盖不到这种非常非常大的数据的场景

另外牛逼一点的静态分析工具也能查到,但是基本上就是个告警,但没人用/当回事

使用字符串 format %一定要注意。这种坑不是一两个了。苹果wifi那个CVE也是%惹的祸

if-switch里可以定义了。这样省一行。比如

switch (Foo foo; foo.getValue()) {
    case 1: //...
            break;
    case 2: //...
            break;
    case 3: //...
            break;
    default:
            //...
            break;
}
...
if (int val = getValue(); val<10) {
    std::cout << "val smaller than 10: " << val << '\n';
} else if (val < 5) {
    std::cout << "val smaller than 5: " << val << '\n';
} else {
    std::cout << "val is bigger than 10: " << val << '\n';
} 

c++17就可以了。

try
{
    Block1;
}
catch (Type1 ex1)
{
    Block2;
}
catch (Type2 const& ex2)
{
    Block3;
}

作者说了一个场景

Block1里有两个栈对象,第一个析构的时候抛异常,被catch了。第二个也跑异常,此时已经catch过了,所以直接std::terminate

c++是没有finally收尾+析构这种模式的,上面这种场景要 如何规避?

流式压缩,效果比facebook哪个gorila还好,挺有意思

视频

整数溢出导致。。。-Wno-error=deprecated -Wsign-conversion -Wconversion 你总得用一个吧

CPPCON

介绍 c++23 的。没啥说的

协程上手,很长

没啥说的

这个有手把手调代码演示,可以看看

代码在这里 https://github.com/sankurm/generic-pipeline

贴一下代码

#include <string>
#include <iostream>
#include <exception>
#include <type_traits>
#include <functional>
#include <fstream>

//The generic implementation also takes care of the return type of Callable being different than T
template<typename T, typename Callable>
auto operator|(T&& val, Callable&& fn) -> typename std::result_of<Callable(T)>::type {
    return std::forward<Callable>(fn)(std::forward<T>(val));
}

//Pre-C++17 code without std::optional
//Code relies on special values like empty string, kafka_config to be convertible to bool and return bools to determine success of a step
namespace
{
    struct env_error : public std::exception {};
    struct file_error : public std::exception {};
    struct json_error : public std::exception {};
    struct creation_error : public std::exception {};
    struct connect_error : public std::exception {};
    struct subscribe_error : public std::exception {};

    std::string get_env(std::string&& varname) {
        if (/* varname not set OR value is empty */false) { throw env_error{}; }
        return "/config/kafka.json";
    }

    std::string get_file_contents(std::string&& filename) {
        std::ifstream file(filename, std::ios::in);
        if (!file && false) { throw file_error{}; }
        return "file-contents-blah-blah";
    }

    struct kafka_config
    {
        /* url etc. */
        operator bool() { return true; }
    };

    enum config_type { json, xml, yaml, config_map };

    template<config_type format>
    kafka_config parse_kafka_config(std::string&& config) {
        if (/* parsing fails == */ false) { throw json_error{}; }
        return kafka_config{};
    }

    struct kafka_consumer
    {
        kafka_consumer(const kafka_config& config) {}
        kafka_consumer(kafka_config&& config) {}

        bool connect() { return true; }
        bool subscribe() { return true; }

        operator bool() { return true; }
    };

    kafka_consumer create_kafka_consumer(kafka_config&& config) {
        return kafka_consumer{std::move(config)};
    }

    kafka_consumer connect(kafka_consumer&& consumer) {
        if (!consumer.connect()) { throw connect_error{}; }
        return consumer;
    }

    auto subscribe = [](kafka_consumer&& consumer) {
        if (!consumer) { throw subscribe_error{}; }
        consumer.subscribe();
        return consumer;
    };

    //Invoking an operation taking more than 1 argument
    //std::bind solution
    kafka_consumer init_kafka() {
        //using namespace std::string_literals;
        //Can use "kafka-config-filename"s as they need C++14
        return std::string("kafka-config-filename")
                | get_env
                | get_file_contents
                | parse_kafka_config<xml>
                | create_kafka_consumer
                | connect
                | subscribe;
    }
}

int main(int argc, char** argv) {
    auto consumer = init_kafka();
    if (consumer) { std::cout << "Consumer creation successful\n"; }
    else { std::cout << "Consumer creation failed\n"; }

    return 0;
}

看个乐。没有scheduler的pipeline操作没啥意义,除了语法糖让自己爽一爽,没别的用处

开源项目需要人手

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

新项目介绍/版本更新

工作招聘

不被开除就不错了


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

本文永久链接

C++ 中文周刊 第85期

21 Oct 12:08
46d24ee
Compare
Choose a tag to compare

reddit/hackernews/lobsters/meetingcpp/purecpp知乎/等等摘抄一些c++动态

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

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

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

公众号也有了

不过没有留言功能

可以贴在下一期草稿里 草稿链接

2022 1021


资讯

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

十月标准委员会邮件汇总

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

2022全球C++及系统软件技术大会演讲嘉宾PPT集合:
https://city.boolan.com/2022_CPPSummit.pdf

2020年的在这里
https://city.boolan.com/2020CPP.pdf

页数很多。没有视频。走马观花随便看看

2022 10.23 purecpp C++大会直播 链接 http://t.csdn.cn/uBRwn

直播内容

文章

基础概念

当我们有一个带GC的编程语言runtime的时候,这个GC该什么时候进行垃圾回收?一般来说,一个runtime会有一个heap limit(L),当程序消耗内存量达到limit后,则会进行垃圾回收,使得内存使用量下降到limit以下。假设程序自己的live set size(无法被GC清掉的,还在用着的内存)是S, 那一般来说,会设置成L = N * S,其中N是一个2之类的常数。这代表着,一个带GC的程序的最大内存使用量,应该是手动内存管理的内存使用量的两倍。但,这其实并不合理!我们在paper里面对垃圾回收进行数学建模,然后寻找一个这个问题的最优解。我们最后发现,应该设置成L = S + N * Sqrt(S),就是说 - S越大,我们对应于原先的算法,应该给的内存越小!这时候,我们的算法在v8 javascript engine上可以比原先的GC快30%(同等内存),又或者同等时间下节省15%的内存

我咋感觉和c++里的vector扩容预留空间不能是简单翻倍而是1.5倍 那种场景有点像,也就是说那种大vector的扩容分配空间可以用这种算法再优化一波

再比如各种buffer pool 管理策略,内存都是钉死的,怎么找到最佳的S呢?

有点意思

给你一个整体的视角,从流水线到cache到虚拟内存 。看图可以点这个

讲SEH的。

__try
{
    Block1;
}
__except (FilterExpression)
{
    Block2;
}
__finally
{
    Block3;
}

乍一看很常规是不是,你再仔细看看有没有遗漏?

FilterExpression有可能异常!如果FilterExpression异常,它是被外层的try包起来的,也就是说,会继续走到__except,会匹配到FilterExpression,会继续异常

最终堆栈溢出程序挂掉

一般遇不到,遇到就会很莫名其妙

之前也聊过,CTAD可能有害,所以要加上告警规避这种场景,但是简单的告警还有可能漏掉某些场景,建议直接-Werror=ctad

vector在move场景是比较保守的,如果T本身不是noexcept move,就copy。本身也是怕T本身move的副作用引发失败,退而求其次保守copy

考虑一个T实现

struct Widget {
    std::list<int> m_ = std::list<int>(1000);
        // MSVC's std::list isn't nothrow movable
};

std::vector<Widget> v(10);
try {
    v.reserve(v.capacity()+1);  // reallocate the buffer
} catch (...) {
    // is v still in its old state?
}

正常的场景,不在乎copy的代价,只要保证Widget没问题就行,强异常处理bad alloc。这样能用没啥问题

如果强异常场景,还要尽可能的move,m_的move可能会有问题,那只好给Widget一个noexcept的move

struct Widget {
    std::list<int> m_ = std::list<int>(1000);
        // MSVC's std::list isn't nothrow movable

    explicit Widget() = default;
    Widget(Widget&&) noexcept = default;  // !!
    Widget(const Widget&) = default;
    Widget& operator=(Widget&&) = default;
    Widget& operator=(const Widget&) = default;
};

std::vector<Widget> v(10);

又想尽可能的move,又想处理bad alloc,其他异常无所谓,做不到,只能自己造一个std::vector了

这个就是作者讨论的类似CAP的那种三角问题

说实话我没怎么理解明白

使用核心内建的功能,而不是库提供的功能

比如 alignof 好过 std::alignment_of_v

static_assert(std::alignment_of_v<Widget> == 8);  // worse
static_assert(alignof(Widget) == 8);  // better

比如alignas好过 std::aligned_storage_t

std::aligned_storage<sizeof(Widget)> data;  // utterly wrong
std::aligned_storage_t<sizeof(Widget)> data;  // still kind of wrong
std::aligned_storage_t<sizeof(Widget), alignof(Widget)> data;  // correct but bad
alignas(Widget) char data[sizeof(Widget)];  // correct and better

比如char好过std::bytes

std::byte data[100];  // worse
char data[100];  // better

int data[10];

// worse
void mycopy(std::byte *dst, const std::byte *src, size_t n);
mycopy((std::byte*)data, (std::byte*)(data+5), 5 * sizeof(int));

// better
void mycopy(void *dst, const void *src, size_t n);
mycopy(data, data+5, 5 * sizeof(int));

lambda 好过bind

range for好过std::for_each

不列代码了

struct好过tuple有名字信息

placement new 好过construct_at

alignas(Widget) char data[sizeof(Widget)];

Widget *pw = std::construct_at((Widget*)data, x, y);  // worse
Widget *pw = ::new ((void*)data) Widget(x, y);  // better

当然这些都是习惯。不强求

依赖计算越长,CPU pipeline越差

为啥unique_ptr构造函数不把make_unique的活给干了??语义不清晰。T里的构造很让人困惑

#include <bitset>
 
constexpr std::bitset<4> b1{"0011"};
static_assert(0b0011 == b1.to_ulong());

constexpr std::bitset<4> b2{0b0011};
static_assert(b1 == b2);

这玩意谁用啊。folly有个省空间的bitset

signum是个很常规的函数

#include <cmath>
float signum_safe(float Value) {
	if( Value < 0.0 )
		return -1.0;
	if( Value > 0.0 )
		return 1.0;
	if( std::isnan(Value) )
		return Value;
	return 0.0;
}

文章讨论用avx512 vfixupimm来实现,并且如何妥善的处理isnan?

视频

直接看代码吧 https://compiler-explorer.com/z/ee8MGrrEY

bind的一种强化

cppcon视频开始放流了,一天一个基本上

讨论值语义的。没能看完

阿里许传奇讲他们应用编译优化的一些经验,LTO, 编译cache,module之类的。没看完。这个英语有点难受。我估计会有中文版的

给我整困了

开源项目需要人手

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

新项目介绍/版本更新


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

本文永久链接

C++ 中文周刊 第84期

14 Oct 13:11
75f70ba
Compare
Choose a tag to compare

C++ 中文周刊 第84期

reddit/hackernews/lobsters/meetingcpp/purecpp知乎/等等摘抄一些c++动态

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

微信公众号下周能上吧

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

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

可以贴在下一期草稿里 草稿链接

2022 10 14


资讯

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

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

文章

正则表达式性能对比,直接贴结果吧。
环境 AMD 线程撕裂者 3960X (Zen2) 3.8 GHz Ubuntu 20.04.5 LTS

蓝的最好红的最差,std::regex就不提了,丢人,你看看rust的regex表现就不错

crte是编译期的 hyperscan是intel开源c++实现,hyperscan遥遥领先

对智能指针取地址,std::addressof, 别用 & 使用上可能有异常场景(比如指针释放)。一半都会有addressof成员函数啥的

省流:Copy­File2 win8之后支持

他的这个压测有点意思

本文的结论如下: 无栈的切换速度要远高于有栈。 无栈协程更加适合IO场景。 无栈协程相比普通函数会有额外开销。

而迄今为止 io uring 已经支持了 48 种异步操作,这四种操作只是冰山一角。本文希望讨论一下如何为 Seastar 加入一部分网络 IO 的 io_uring 支持。

可以看看。有点意思。另外这个哥们也是seastar/ceph开发者,博客写的不错

这个是iouring相关MR scylladb/seastar#1235

这几个经验还是挺有意思的,比如magic字符串,以及多租户场景下轻易别退出。。。(这个我也遇到过)

很值得一看,一看就知道线上的惨烈了,我是笑着看完的

concept作为接口的一部分

#include <concepts>

void foo(int i);
void bar(std::same_as<int> auto i);


int main() {
  foo(42.0); // 隐式转换
  bar(42.0); // 编译不过
}

c++程序员没有不知道的吧,没有就再普及一遍

草药老师又在讲设计了。没细看

为啥用wasm不用luajit lua +jit不能做沙盒么?

视频

推荐了一堆网络库

讲的挺基础的。可以看看

开源项目需要人手

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

新项目介绍/版本更新


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

本文永久链接

C++ 中文周刊 第83期

08 Oct 07:06
0fb7393
Compare
Choose a tag to compare

C++ 中文周刊 第83期

reddit/hackernews/lobsters/meetingcpp/purecpp知乎/等等摘抄一些c++动态

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

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

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

可以贴在下一期草稿里 草稿链接

2022 1008


资讯

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

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

文章

直接贴个代码 https://godbolt.org/z/Yxc58vrWW

cppfront的设计。看个乐。草木大哥上次玩的constraint也探索了好几年。这个玩意我估计也得玩几年。不会进。只是提供个思路

众所周知,range for里的临时变量左值有问题

class Keeper {  
  std::vector<int> data{2, 3, 4};
public:
  ~Keeper() { std::cout << "dtor\n"; }
  // Returns by reference
  auto& items() { return data; }
};
// Returns by value
Keeper GetKeeper() {
  return {};
}
void Use() {
  // ① Use the result of GetKeeper and return
  // over items
  for(auto& item : GetKeeper().items()) {
    std::cout << item << '\n';
  }
}

这个遍历很有可能挂掉。UB。但是我非要这么写,keeper类怎么设计呢?

class Keeper {
  std::vector<int> data{2, 3, 4};
public:
  ~Keeper() { std::cout << "dtor\n"; }
  auto& items() & { return data; }
  // ④ For rvalues, by value with move
  auto items() && { return std::move(data); }
};

注意这两个items后面的&限定,两种限定约定了被调用的时候走左还是右值,如果是range for循环,就调用第二个items,救一下data的生命,就没问题了。

我觉得还是尽量别range for里乱搞。容易误用。有的类设计类这种方法,如果有的类没这么设计,不就完了。

周所周知,临时变量的生命周期是一行,来一个复杂的例子

考虑一行上锁自动解锁

template<typename> struct LockableData;

namespace std
{
    template<typename Data>
    struct default_delete<LockableData<Data>>
    {
        void operator()(LockableData<Data>* p)
        const noexcept { p->m.unlock(); }
    };
}

template<typename Lockable>
struct [[nodiscard]] LockedData
{
    LockedData(Lockable* l = nullptr) : l(l)
    { if (l) l->m.lock(); }

    auto operator->() const noexcept
    { return std::addressof(l->data); }

private:
    std::unique_ptr<Lockable> l;
};

template<typename Data>
struct LockableData
{
    LockedData<LockableData> Lock() { return this; }

private:
    friend struct LockedData<LockableData>;
    friend struct std::default_delete<LockableData>;

    std::mutex m;
    Data data;
};

使用例子

struct WidgetInfo
{
    std::string name;
    int times_toggled = 0;
};

class Widget
{
    LockableData<WidgetInfo> info;

public:
    void SetName(std::string name)
    {
        auto lock = info.Lock();
        lock->name = name;
        lock->times_toggled = 0;
    }

    std::string GetName()
    {
        auto lock = info.Lock();
        return lock->name;
    }

    void Toggle()
    {
        { // scope the lock
            auto lock = info.Lock();
            lock->times_toggled++;
        }
        FlipSwitchesRandomly();
    }
};

目前来看还是没啥问题,但是要多一个lock,很自然的,你想到了省略这一行

template<typename Data>
struct LockableData
{
    LockedData<LockableData> Lock() { return this; }
    auto operator->() { return Lock(); } // NEW!

private:
    friend struct LockedData<LockableData>;
    friend struct std::default_delete<LockableData>;

    std::mutex m;
    Data data;
};

class Widget
{
    LockableData<WidgetInfo> info;

public:
    void SetName(std::string name)
    {
        auto lock = info.Lock();
        lock->name = name;
        lock->times_toggled = 0;
    }

    std::string GetName()
    {
        return info->name; // lock-read-unlock
    }

    void Toggle()
    {
        info->times_toggled++; // lock-modify-unlock
        FlipSwitchesRandomly();
    }
};

问题来了。info->调用生成了一个临时对象,临时对象这一行结束就释放了,可能会出现读的不一样的问题,但这问题不大,真正的问题是这种用法可能导致锁两次

比如上面这个toggle,伪代码

    // Evaluate right hand side
    LockedData<WidgetInfo> lock1 = info.operator->();
    int rhs = std::max(lock1->times_toggled, 10);

    // Evaluate left hand side
    LockedData<WidgetInfo> lock2 = info.operator->();

    // Perform the assignment
    lock2->times_toggled = rhs;

    // Destruct temporaries in reverse order of construction
    destruct lock2;
    destruct rhs;
    destruct lock1;

明显锁了两次。可能->这个方法过于有问题,我直接调用,比如

    std::string GetName()
    {
        return info.Lock()->name;
    }

应该不会有问题了吧, 如果toggle这么实现

    void Toggle()
    {
        // suspicious double-lock - more likely to be spotted in code review
        info.Lock()->times_toggled = std::max(info.Lock()->times_toggled, 10);
        FlipSwitchesRandomly();
    }

也是有同样问题的

RAII的烦恼也很多啊。解决方法可能是out_ptr或者std::synchronized_value folly::synchronize这种类似的玩意。别自己写了。可能想不到

不太懂

分析了一波,是编译器bug。msvc 16.10 以下的版本有问题,修复记录 https://devblogs.microsoft.com/cppblog/cpp20-coroutine-improvements-in-visual-studio-2019-version-16-11/

用concept实现crtp。之前也介绍过类似的

// we create a concept can_work to check if do_work is implemented
// this will describe our interface
template <typename T>
concept can_work = requires(T t) {
    t.do_work();
};

// now we apply this concept to an empty type which represents a worker (or our base class)
template<can_work T>
struct worker : public T {};

// now create a concrete worker (corresponding derived) where we implement do_work
struct concrete_worker {
    void do_work() {
        // ...
    }
};

// nice to have: an alias for our concrete worker
using my_worker = worker<concrete_worker>;

//...
// which we can use now
my_worker w;
w.do_work();

面向接口的感觉

没啥说的。c++23就能用了。之前你可以用absl的或者boost的。都差不多

一个COW vector大概的样子

template <class T>
class CowVector {
    struct State {
        std::atomic<int> ref;
        size_t size;
        size_t capacity;

        T elements[];
    }
    State* state;

    // if we're not unique, we need to allocate
    // a new State and copy the elements.
    // if we are unique, this is a no-op.
    void copy_on_write();

public:
    // copy constructor *never* allocates.
    // just increments ref-count
    CowVector(CowVector const& rhs)
        : state(rhs.state)
    {
        ++state->ref;
    }

    // and the mutable and const accessors do different things
    auto operator[](size_t idx) -> T& {
        copy_on_write();
        return state->elements[idx];
    }

    auto operator[](size_t idx) const -> T const& {
        return state->elements[idx];
    }
};

怎么更干净更灵活的copy_on_write? 这套代码怎么用 Deducing this 改写

template <class T>
class CowVector {
public:
    auto operator[](this CowVector& self, size_t idx) -> T&;
    auto operator[](this CowVector const& self, size_t idx) -> T const&;
};

Self应该模版化

template <class T>
class CowVector {
    struct State { ... };
    State* state;

    // this one (potentially) copies
    auto get_state() -> State*;

    // this one doesn't, because const
    auto get_state() const -> State const* { return state; }
public:
    template <class Self>
    auto operator[](this Self& self, size_t idx)
        -> std::copy_const_t<Self, T>&
    {
        return self.get_state()->elements[idx];
    }
};

里面还讨论了很多边角场景,感兴趣的可以看看

一个map存数据,如果存在就不插入

object* retrieve_or_create(int id)
{
  static std::unordered_map<int, std::unique_ptr<object>> m;

  // see if the object is already in the map
  auto [it,b] = m.emplace(id, nullptr);
  // create it otherwise
  if(b) it->second = std::make_unique<object>(id); 
  return it->second.get();
}

很常规。问题在于object可能非常大,可能构造异常。try catch一下,正好有try_emplace这个接口

object* retrieve_or_create(int id)
{
  static std::unordered_map<int, std::unique_ptr<object>> m;

  auto [it,b] = m.try_emplace(id, std::make_unique<object>(id));
  return it->second.get();
}

但是问题并没有解决,我们希望的是,直到需要调用make的时候,再调用。推迟到emplace 那一刻

template<typename F>
struct deferred_call
{
  using result_type=decltype(std::declval<const F>()());
  operator result_type() const { return f(); }

  F f;
};

object* retrieve_or_create(int id)
{
  static std::unordered_map<int, std::unique_ptr<object>> m;

  auto [it,b] = m.try_emplace(
    id,
    deferred_c...
Read more

C++ 中文周刊 第82期

03 Oct 04:11
Compare
Choose a tag to compare

C++ 中文周刊 第82期

reddit/hackernews/lobsters/meetingcpp/purecpp/知乎/等等摘抄一些c++动态

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

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

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

可以贴在下一期草稿里 草稿链接

2022 1002

大家国庆快乐


资讯

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

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

文章

除了贵和积热之外没啥缺点。zen4太贵了。本来打算双十一拼一台。看样子只能考虑明年618再拼了。

今年可以双十一攒个5950x,加b550不到四千。内存也便宜

struct s {
  static constexpr auto operator()() { return 1; }
};
auto l = [] static { return 2; };

static_assert(3 == s{}() + l());

static_assert(3 == s::operator()() +
         decltype(l)::operator()());

没啥说的。补全一下

有了ssize支持,可以不考虑符号了,

for (int i = 0; i < ssize(vec); ++i)
    std::cout << i << ": " << vec[i] << '\n';

range遍历 + 索引

int main() {
    std::vector vec { 1, 2, 3, 4, 5};
    for (int i = 0; const auto& elem : vec)
        std::cout << i++ << ": " << elem << '\n';
}

说实话有点别扭,没有go那种 i, v = range那种感觉好, 聊胜于无吧

组合view

#include <iostream>
#include <vector>
#include <ranges>

int main() {
    std::vector vec { 1, 2, 3, 4, 5};
    for (int i = 0; const auto& elem : vec | std::views::reverse)
        std::cout << i++ << ": " << elem << '\n';
}

使用range view算法

void printReverse(auto cont) {
    std::ranges::for_each(cont | std::views::reverse, 
        [i=0](const auto& elem) mutable {
            std::cout << i++ << ' ' << elem << '\n';
        }
    );
}

看不懂

科普一下

还是科普

这个其实就是之前那个英语博客的转述

草药老师关于他cppfront语法的一些需求的实现。没细看

介绍format以及llvm的支持程度。基本都支持除了chrono

内联场景的前缀字符串前缀数组可能会被编译器优化掉,减少二进制大小

比如

    const char * str1 = "dear friend";
    const char * str2 = "dear friend";
    return str1 == str2;
void oops(std::vector<std::string>& v)
{
    set_name(v.front.c_str());
    //         ^^^^^ error: A pointer to a bound function
    //         may only be used to call the function
}

忘记加括号了

有些功能比如move迭代器之类的存在用不好的场景。导致莫名其妙的影响性能。

视频

类型擦除的方法。之前也讲过. 就是藏函数指针

class animal_view {
 public:
  template <typename Speakable>
  explicit animal_view(const Speakable &speakable)
      : object{&speakable},
        speak_impl{// create a lambda that knows how to unpack the stored object
                   [](const void *obj) {
                     return static_cast<const Speakable *>(obj)->speak();
                   }} {}

  void speak() const { speak_impl(object); }

 private:
  // void * to object of unknown type
  const void *object;

  // function pointer that knows how to use unknown type
  void (*speak_impl)(const void *);
};

void do_animal_things(animal_view animal) { animal.speak(); }

int main() {
  struct Cow {
    void speak() const { fmt::print("Mooo\n"); }
  };

  struct Sheep {
    void speak() const { fmt::print("Baaa\n"); }
  };
  do_animal_things(animal_view{Cow{}});
  do_animal_things(animal_view{Sheep{}});
}

开源项目需要人手

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

新项目介绍/版本更新

  • cppq 一个基于redis的任务队列

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

本文永久链接

C++ 中文周刊 第81期

23 Sep 10:12
0e4e4c9
Compare
Choose a tag to compare

reddit/hackernews/lobsters/meetingcpp/知乎等等摘抄一些c++动态

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

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

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

可以贴在下一期草稿里 草稿链接

2022 09 23

马上就国庆节了。节前节后这两周大概率没时间更新了。提前祝大家节日快乐。好好休息


资讯

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

九月讨论汇总 https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/#mailing2022-09

polymorphic_allocator<> instead of type-erasure

这个有点意思,众所周知,std::function用malloc,不能指定allocator,挺坑。如果std::function创建多了。malloc倒是成为瓶颈了。坑。
主要是加个 using allocator_type = std::pmr::polymorphic_allocator<>;

function_ref: a type-erased callable reference

这个讨论好久了。

Proxy: A Polymorphic Programming Library

这个也介绍过,是微软搞的类似folly::poly那种用户态的多态实现。

别的没啥说的。修修补补

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

另外还有Azure CTO说c++不行了新项目转rust。c++老大说他喜新厌旧。具体大家搜一搜就好了。不贴出来了。有点八卦

问题在这里 https://www.zhihu.com/question/554750609

文章

这个分配器确实不错。差点项目里就用了。后来研究了一下发现checkpoint麻烦就放弃了。这个设计还是很有意思的

介绍防守编程的,_FORTIFY_SOURCE=3新级别,更严格,能抓到buffer overflow

被符号不匹配告警搞烦了

template <typename T>
bool has_repeated_values(const T& container) {
  for (int i = 0; i < container.size() - 1; ++i) {
    if (container[i] == container[i + 1]) return true;
  }
  return false;
}
// 修改后

std::vector vec = ...
if (!empty(vec)) {
    for (int i = 1; i < ssize(vec); ...) {
        ...
    }
}

内部帮你static_cast。快谢谢库作者

看看见识见识

介绍各个平台系统api兼容性

介绍msvc告警的。没啥说的

不太懂windows下的汇编表现

看不太懂

视频

介绍cppfront herb大哥整的新活, cpp2。看个乐

这里有个介绍 https://www.zhihu.com/question/536288519/answer/2682665038

介绍range。没啥说的

开源项目需要人手

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

新项目介绍/版本更新

  • lager 一个UI框架,类似redux

工作招聘

哎。虾皮突发变动搞的人心惶惶啊。


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

本文永久链接

C++ 中文周刊 第80期

16 Sep 12:29
e01cfe8
Compare
Choose a tag to compare

reddit/hackernews/lobsters/meetingcpp知乎等等摘抄一些c++动态

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

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

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

可以贴在下一期草稿里 草稿链接

2022 0916


资讯

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

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

cppcon 2022还在进行中。视频放了几个。没看。有参与者说今年不太行。我去年还没怎么看。看视频信息量太低了。得看PPT然后找视频看。最近没啥空。周末有时间可以看看

文章

打印堆栈支持。看代码

#include <stacktrace>
#include <iostream>

int foo() {
  std::cout << std::stacktrace::current();
  return {};
}

int main() {
  return foo();
}

可算支持了

各个编译器Modules支持的状态进展介绍

标准库的std::optional是不支持T&和void的。作者说了下自己可能会用到这个场景,标准库应该加上

之前介绍过。介绍了谷歌浏览器团队在解决指针问题的一些实践。实现了很多,但是有些文档不可见。

也介绍了其他方案的实现,比如这个unowned_ptr

代码难找就没有深入研究。不过讨论还是值得一看的。我后面整理一下

介绍Sanitizer

seastar代码走读

注意co_await的阻塞语义,永远超时导致不能使用

四舍五入等于c的东西。可以看个热闹

各种容器介绍,比如folly::fbvector, boost::small_vector等等。感兴趣的可以看看

写了个工具验证gcc产出的代码对不对,具体就是验证gimple IR。我不太懂。感兴趣可以看看

office团队要用module,这是msvc团队的一些探索

介绍msvc调试的。没用过不了解,有没有懂的给讲讲

代码长这样

struct WidgetTracker : IWidgetChangeNotificationSink
{
    /* other stuff not relevant here */

    /// IWidgetChangeNotificationSink
    STDMETHODIMP OnCurrentWidgetChanged();

private:
    WRL::ComPtr<IWidget> m_currentWidget;
    std::mutex m_mutex;
};

HRESULT WidgetTracker::OnCurrentWidgetChanged()
{
    auto guard = std::lock_guard(m_mutex);
    RETURN_IF_FAILED(GetCurrentWidget(&m_currentWidget));
    return S_OK;
}

OnCurrentWidgetChanged是个回调,如果m_currentWidget变了就会被调用

问题在于OnCurrentWidgetChanged被调用这个m_mutex锁住的瞬间,m_currentWidget析构,结果又触发一次OnCurrentWidgetChanged,导致死锁

这个问题根源在于锁锁不住comptr,无法避免递归调用。

解决方法也很简单,拷贝一份对象就行了。

HRESULT WidgetTracker::OnCurrentWidgetChanged()
{
    WRL::ComPtr<IWidget> widget; // 可能别人在用它
    auto guard = std::lock_guard(m_mutex);
    RETURN_IF_FAILED(GetCurrentWidget(&widget));
    m_currentWidget.Swap(widget);
    return S_OK;
}

作者之前讨论过一段类似的代码,用的,shared_ptr, 也有相同的问题

class ThingManager
{
private:
  std::mutex things_lock_;
  std::vector<std::shared_ptr<Thing>> things_;

public:
  void AddThing(std::shared_ptr<Thing> thing)
  {
    std::lock_guard guard(things_lock_);
    things_.push_back(std::move(thing));
  }

  void RemoveThingById(int32_t id)
  {
    std::lock_guard guard(things_lock_);
    auto it = std::find_if(things_.begin(), things_.end(),
      [&](auto&& thing)
      {
        return thing->id() == id;
      });
    if (it != things_.end()) {
      things_.erase(it);
    }
  }
};

class SuperThing : Thing
{
private:
  ThingManager& manager_;
  int32_t helper_id_ = 0;

public:
  SuperThing(ThingManager& manager) :
    manager_(manager)
  {
    auto helper = std::make_shared<Thing>();
    helper_id_ = helper->id();
    manager_.AddThing(helper);
  }

  ~SuperThing()
  {
    manager_.RemoveThingById(helper_id_);
  }
};

void test(ThingManager& manager)
{
  auto s = std::make_shared<SuperThing>(manager);
  auto id = s->id();
  manager.AddThing(s);
  s = nullptr; // 1

  manager.RemoveThingById(id); // 2
}

问题是相同的,同一个锁被锁两次。如何触发?首先SuperThing会在2 这行真正的析构,1那行只会引用计数-1
RemoveThingById(id)是会锁的,内部触发了SuperThing析构,然后又调用了manager_.RemoveThingById(helper_id_);,锁了同一个锁

你可能觉得这种代码写的有问题。这是锁和shared_ptr和坑爹析构三个同时引入引发的问题,我遇不到

解决方法也很简单。让这个shared_ptr活着,因为不知道哪个外部调用会用到这个shared_ptr

void RemoveThingById(int32_t id)
{
  std::shared_ptr removed_thing; // 求求你活着
  {
    std::lock_guard guard(things_lock_);
    auto it = std::find_if(things_.begin(), things_.end(), ...);
    if (it != things_.end()) {
      removed_thing = *it;
      things_.erase(it);
    }
  }
}

引用计数指针和锁的问题。这里打个问号。要注意

oldnewthing的博客真精彩,总能遇到各种莫名其妙的bug

标准库提供了新函数来更友好的判断整数大小,不用自己写那些符号转换逻辑了

比如

template <class _Ty1, class _Ty2>
_NODISCARD constexpr bool cmp_equal(const _Ty1 _Left, const _Ty2 _Right) noexcept {
  static_assert(_Is_standard_integer<_Ty1> && _Is_standard_integer<_Ty2>,
   "The integer comparison functions only "
   "accept standard and extended integer types.");
  if constexpr (is_signed_v<_Ty1> == is_signed_v<_Ty2>) {
    return _Left == _Right;
  } else if constexpr (is_signed_v<_Ty2>) {
    return _Left == static_cast<make_unsigned_t<_Ty2>>(_Right) && _Right >= 0;
  } else {
    return static_cast<make_unsigned_t<_Ty1>>(_Left) == _Right && _Left >= 0;
  }
}
VPSUBUSB	z, x, y

VPMINUB		z, x, y
VPCMPEQB	w, z, x

我不太懂。不评价

用avx处理字符串中的斜杠,比如my title is \"La vie\"

通常写法

  for (...) {
    if ((*in == '\\') || (*in == '"')) {
      *out++ = '\\';
    }
    *out++ = *in;
  }

sse/avx写法

 __m512i solidus = _mm512_set1_epi8('\\');
  __m512i quote = _mm512_set1_epi8('"');
  for (; in + 32 <= finalin; in += 32) {
    __m256i input = _mm256_loadu_si256(in);
    __m512i input1 = _mm512_cvtepu8_epi16(input);
    __mmask64 is_solidus = _mm512_cmpeq_epi8_mask(input1, solidus);
    __mmask64 is_quote = _mm512_cmpeq_epi8_mask(input1, quote);
    __mmask64 is_quote_or_solidus = _kor_mask64(is_solidus, is_quote);
    __mmask64 to_keep = _kor_mask64(is_quote_or_solidus, 0xaaaaaaaaaaaaaaaa);
    __m512i shifted_input1 = _mm512_bslli_epi128(input1, 1);
    __m512i escaped =
        _mm512_mask_blend_epi8(is_quote_or_solidus, shifted_input1, solidus);
    _mm512_mask_compressstoreu_epi8(out, to_keep, escaped);
    out += _mm_popcnt_u64(_cvtmask64_u64(to_keep));
  }

给我看困了

这里有个类似的https://branchfree.org/2019/03/06/code-fragment-finding-quote-pairs-with-carry-less-multiply-pclmulqdq/

这段代码有bug,不懂这几个API的可能看不懂

bool ShuttingDown = false;

void MainThread()
{
    DWORD id;
    auto hThread = CreateThread(nullptr, 0, WorkerThread,
                                nullptr, 0, &id); // succeeds

    BlahBlahBlah(); // do useful work

    // Time to clean up. Post an APC to the worker thread
    // to tell it that it's time to go home.
    QueueUserAPC(WakeWorker, hThread, 0); // succeeds

    WaitForSingleObject(hThread, INFINITE); // hangs

    CloseHandle(hThread);
}

void CALLBACK WakeWorker(ULONG_PTR)
{
    ShuttingDown = true;
}

DWORD CALLBACK WorkerThread(void*)
{
    // Do work until shut down.
    do
    {
        // All work is posted via APCs.
        SleepEx(INFINITE, TRUE);
    } while (!ShuttingDown);

    return 0;
}

简单来说SleepEx通过QueueUserAPC来唤醒,有一种场景,QueueUserAPC唤醒了,但是CreateThread执行的慢,导致SleepEx没收到通知,从而永远死锁

怎么解决这个问题?把do while循环改成while就行了。因为这种场景已经shutdown了,不应该执行sleep

DWORD CALLBACK WorkerThread(void*)
{
    // Do work until shut down.
    while (!ShuttingDown)
    {
        // All work is posted via APCs.
        SleepEx(INFINITE, TRUE);
    } 

    return 0;
}

讲协程的。说来惭愧我还不是很懂。就不介绍了

视频

  • [C++ Weekly - E...
Read more

C++ 中文周刊 第79期

09 Sep 07:09
Compare
Choose a tag to compare

reddit/hackernews/lobsters/purecpp知乎等等摘抄一些c++动态

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

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

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

可以贴在下一期草稿里 草稿链接

2022 0908 提前发了。周五有事

资讯

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

llvm 15发布了。c++20支持等等一大堆修改

lld 15 ELF changes

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

文章

要注意协程被线程切换影响

c++23详细总结

c++20应用协程举例

std::function的分析

seastar的一些代码走读。可以看看

其实就是编译期检测接口的能力

一组协程教程

#include <ranges>

template <auto Begin, auto End, auto List>
auto slice = List
           | std::ranges::views::drop(Begin)
           | std::ranges::views::take(End);

static_assert(
  slice<1_c, 2_c, boost::mp::list<int, double, float>()>
  ==
                  boost::mp::list<double, float>());

typelist实现更简单了。恐怖

optinal的move并不会真正的move T, 让T为无效value

template <typename T>
void test(T v)
{
  optional<T> o = v;
  assert (o);     // o contains a value
  optional<T> p = std::move(o);
  assert (o);     // o still contains a value!
}

完全取决于T的move,optional会保留T的壳子。

比如unique_ptr

int * p = new int(1);
 
optional<unique_ptr<int>> op = unique_ptr<int>(p);
assert (op);
assert (op->get() == p);
 
optional<unique_ptr<int>> o2 = std::move(op);
assert (op);                   // still contains a value
assert (op->get() == nullptr); // the value is moved from
assert (o2);
assert (o2->get() == p);

unique_ptr内部会搬走,但本身是还在optional里的。这样实现更快,对于trival类型,这样优化的可以直接memcpy,更高效一些
大概实现成这个样子

template <typename Trivial>
class optional<Trivial>
{
  bool     _is_initialized;
  Trivial  _value;
 
  optional() : _is_initialized(false) {}
  // use defaulted copy and move 
};
// Second argument is a pointer to the type of std::fclose, we could also have
// written it out explicitly as std::unique_ptr<FILE, int (*)(FILE*)>.
using FilePtr = std::unique_ptr<FILE, decltype(std::fclose) *>;

// Instantiate the FILE* with the destructor we want.
FilePtr file(std::fopen(filename, "rbe"), std::fclose);

// Do stuff with the file
std::fread(buf_.data(), 1, buf_.size(), file.get());

比写个deferGuard能更干净些

using XXH3StatePtr = std::unique_ptr<XXH3_state_t, decltype(XX3_freeState) *>;
XXH3StatePtr state(XXH3_createState(), XXh3_freeState);

但这种写法的问题在于,需要判定创建失败/指针是否有效

一个简单的函数

[[nodiscard]] auto say_a_to(
    std::string_view what, std::string_view name) -> std::string {
  return std::string{what} + ", " + std::string{name} + "!";
}

say_a_to("Hi", "Kate"); // -> "Hi, Kate!"

struct {
  [[nodiscard]] auto operator()(
      std::string_view what, std::string_view name) const -> std::string {
    return std::string{what} + ", " + std::string{name} + "!";
  }
} say_b_to;

say_b_to("Hello", "Tony"); // -> "Hello, Tony!"

没啥新奇的,但是c++23支持多维数组了,所以说operator[] 也算是一种函数了

比如

struct {
  [[nodiscard]] auto operator[](
      std::string_view what, std::string_view name) const -> std::string {
    return std::string{what} + ", " + std::string{name} + "!";
  }
} say_d_to;

say_d_to["Goodbye", "Tony"]; // -> "Goodbye, Tony!"
struct {
  template <std::integral ...Ts>
  [[nodiscard]] auto operator[](Ts... ts) const noexcept {
    return (0 + ... + ts);
  }
} sum;
const auto s1 = sum[1, 2, 3]; // 6
const auto s2 = sum[];        // 0

我只能说看个乐,别这么写求求了

视频

#include <iostream>
#include <ranges>
#include <string_view>

int main() {

  // this is lazily evaluated
  auto strings = std::string_view{"Hello C++ 20"} | std::views::split(' ');

  // the result is a range of ranges
  
  for (const auto &ref : strings) {
    // C++ 20
    std::cout << '\n' << std::string_view{ref.begin(), ref.end()};
    // C++ 23
    std::cout << '\n' << std::string_view{ref};
  }
}

开源项目需要人手

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

工作招聘

寒冬了

华为出新手机了,但我不买,因为想把寒冬传给它

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

本文永久链接

C++ 中文周刊 第78期

02 Sep 13:28
d25cee6
Compare
Choose a tag to compare

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

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

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

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

可以贴在下一期草稿里 草稿链接

2020 09 02


资讯

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

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

文章

尽量让move 构造函数 noexcept, 不然用vector可能有问题,多copy

比如这个

struct Instrument {
    int n_;
    std::string s_;

    Instrument(const Instrument&) = default;

    // WRONG!!
    Instrument(Instrument&& rhs)
        : n_(std::exchange(rhs.n_, 0)),
          s_(std::move(s_))
        {}

    // RIGHT!!
    Instrument(Instrument&& rhs) noexcept
        : n_(std::exchange(rhs.n_, 0)),
          s_(std::move(s_))
        {}
};

如果不是noexcept,vector的move判定内部的T不是is_nothrow_move_constructible, 那就构造复制一份,所以多了个拷贝。也就是博主说的vector pessimization问题

vector本身的搬迁move的多余动作,如果能nothrow,move就更简单

free没有size看上去是个巧妙的设计,实际上隐含了挺多脏活

协程背后都做了啥

有点意思

struct foo {
   [[nodiscard]] foo(auto& resource) {}
};

struct [[nodiscard]] bar {};

auto fn() -> bar;

[[nodiscard]] auto fn2() -> bool;

int main(int, char** argv){
    foo{argv}; // ignoring temp created by [[nodiscard]]
    fn();      // ignoring return value with [[nodiscard]]
    fn2();     // ignoring return value with [[nodiscard]]
}

老文,科普一下概念。

参数不是constexpr

consteval auto square(int x) -> int { return x * x; }

constexpr auto twice_square(int x) -> int { return square(x); }

编译不过。作者展示了一下编译期计算。哎又回去了。constexpr还是不够const

看个乐

介绍这几个flag

-march=native肯定接触过吧

茴香豆的茴的20种写法

为什么大哥解bug这么熟练

视频

static constexpr 和 inline constexpr区别。inline constexpr能合并文件重复的数据,是文件级别,static是函数级别,并不能合并代码段

聪明的你想到了static inline constexpr。这个效果就是static constexpr。static限制了范围

开源项目需要人手

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

工作招聘

寒冬了


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

本文永久链接

C++ 中文周刊 第77期

26 Aug 11:50
67f934a
Compare
Choose a tag to compare

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

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

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

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

可以贴在下一期草稿里 链接

2022 08 26

准备做视频,目前有代码走读/benchmark俩主题,大家还有啥意见可以供稿一下。下一期视频准备先来个userver代码走读。我先准备准备材料


资讯

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

标准委员会八月邮件 https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/#mailing2022-08

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

文章

namespace detail {
template <bool> struct conditional;
template <> struct conditional<false> {
  template <class, class T> using fn = T;
};
template <> struct conditional<true> {
  template <class T, class> using fn = T;
};
} // namespace detail

template <bool B, typename T, typename F>
using conditional_t = typename detail::conditional<B>::template fn<T, F>;

说实话,没看懂

关于协程的封装探索,挺有意思的

看不懂

GCC整体介绍

看个乐

fmt对输出有严格限制

介绍他自己写的静态检查器 https://github.com/GregUtas/robust-services-core

main函数执行前都干了啥,填充入参之类的

#include <iostream>
#include <string>
#include <stdlib.h>

std::string message;

extern "C" {
void __asan_on_error() {
  std::cout << "You caused an error: " << message << std::endl;
}
}


int main() {
  int array[8];
  for(int k = 0;; k++) {
    message = std::string("access at ") + std::to_string(k);
    array[k] = 0;
  }
  return EXIT_SUCCESS;
}

不过不太实用

memcmp比较出错。qemu这种牛逼软件也会有这种问题啊

int arr[10000];    // 一个已有的数组
mdspan mdarr{arr, i, j, k};  // 把已有的数组 arr 视作 i×j×k 的多维数组
int value = mdarr[x, y, z];  // 访问多维数组的元素
mdarr[x, y, z] = 42;         // 向元素赋值

简而言之就是这几行。现在你已经学会了

视频

-ftime-trace 生成编译的时间json结果,可以用chrome://tracing/ 浏览器来加载查看。可以自己试一试

觉得麻烦想快速验证的,这里有个build bench https://build-bench.com/b/zLopSp4Yj5XaijZSuwqiYvA2PNU

开源项目需要人手

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

新项目介绍/版本更新

工作招聘

突然寒冬卧槽了,任正非你这嘴开过光吧


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

本文永久链接