周刊项目地址[1]
RSS https://github.com/wanghenshui/cppweeklynews/releases.atom
欢迎投稿,推荐或自荐文章/软件/资源等
请提交 issue[2]
感谢 YellyHornby fengyiee木马 不语 赞助
加了个互动栏目,欢迎各位投稿
奇妙的BUG
欢迎投稿
资讯
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 OSDT Weekly 2023-10-04 第222期
cppcon 2023 已经发了四个视频了,BS又在讲安全,另外几个过于抽象,所以我本期还是主要更新cppcon 2022 的内容
九月邮件列表 https://isocpp.org//blog/2023/10/2023-09-mailing-available
libcurl 最近cve很严重,推荐升级8.4.0
文章
Did you know about C 26 proposal - inplace_vector? [3]
代码语言:javascript复制int main() {
std::inplace_vector<int, 2> v{};
assert(v.empty());
v.push_back(1);
assert(1 == v.size());
v.push_back(2);
assert(2 == v.size());
v.push_back(3); // throws
}
代码语言:javascript复制
就是boost static_vector 可以尝鲜使用
不明表标准委员会对于这个static_vector有啥不满意的,inplace_vector这名也莫名其妙
C :constexpr的数学库[4]
C :constexpr的数学库(二)[5]
这哥们等不及标准库 自己实现了一波constexpr
其实社区也有人做了 https://github.com/kthohr/gcem
C 成员指针完全解析(pointer to member)[6])
基础知识
现代 C 及其在 ClickHouse 中的应用[7]
基础知识,值得看一遍
C 实用技巧之 defer[8]
直接贴代码吧,感觉都见过了
代码语言:javascript复制template <typename Fn>
class Defer {
const Fn& fn_;
public:
Defer(const Fn& fn) noexcept : fn_{fn} {}
~Defer() noexcept {
fn_();
}
Defer(Defer&&) = delete;
};
#define DEFER_PASTE_(x, y) x##y
#define DEFER_CAT_(x, y) DEFER_PASTE_(x, y)
#define DEFER(...) Defer DEFER_CAT_(defer_, __LINE__){__VA_ARGS__}
void f() {
auto res = somelib_alloc();
DEFER([res]() { somelib_free(res); });
// do with res
}
Type Sequence and Factory Method[9]
之前写过类似的,是根据type 用宏之类的拿到字符串,然后映射成type map
string name -> id -> class
他这个实现比较简单,就是就是string -> class指针,不是映射成type的形式
构造的时候批量构造,免得一个一个注册
核心代码
代码语言:javascript复制
代码语言:javascript复制template <class... T>
struct type_sequence{};
// AA trick 看这个 https://www.youtube.com/watch?v=va9I2qivBOA
using dinasour_types = type_sequence<
Diplodocus,
Stegosaurus,
Tyrannosaurus
>;
template <class T>
std::unique_ptr<Dinosaur> make_unique_dino() {
return std::make_unique<T>();
}
template <class... Ts>
std::unique_ptr<Dinosaur> make_dinosaur_from(type_sequence<Ts...>, std::string_view name) {
static std::unordered_map dinosaur_map {
std::pair {get_typename<Ts>(), &make_unique_dino<Ts>} ...
};
if (auto it = dinosaur_map.find(std::string(name)); it != dinosaur_map.end()) {
auto fn = it->second;
return fn();
}
return nullptr;
}
std::unique_ptr<Dinosaur> make_dinosaur(std::string_view name) {
return make_dinosaur_from(dinasour_types{}, name);
}
Are Function Pointers and Virtual Functions Really Slow? [10])
测下来发现基本没差,与其压测时间,不如看cycle
绑定指针毕竟是C里面的老OOP技巧,虚指针不过是自动化了这个动作
视频
cppcon 2023
BS还在safe 草药老师还在那里cpp2,我劝cpp这帮老头务实一点,别搞这些虚头八脑的
想看的 b站搜 BV1BC4y1R7iL
cppcon 2022
- • Aliasing-Roi-Barkan
这个感觉说过
就是各种各样的歧义(别名)问题,多个指针(引用)指向同一个地址,然后误用了
比如string
代码语言:javascript复制std::string s{“hello, ”};
s = s;
比如指针
代码语言:javascript复制// 这个函数设计就很坑爹
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"};
minmax(arr[0], arr[1], &arr[0], &arr[1]);
再比如引用,当然引用也是指针
代码语言:javascript复制auto concat = [](string& result, const auto&... args) {
((result = args), ...);
};
string x{"hello "}, y{"world "};
concat(x, y, x);
再比如成员变量
代码语言:javascript复制
complex<int> x{2, 2};
x *= reinterpret_cast<int*>(&x)[0];
再比如lambda的引用捕获,还是指针
代码语言:javascript复制auto add_to_all = [](auto& v, const auto& val) {
for_each(begin(v), end(v), [&](auto& x) { x = val; });
};
vector<int> v{1, 2, 3};
add_to_all(v, v[0]);
经典的buffer重叠,没有什么比char*更指针的玩意了
代码语言:javascript复制#include <cstring>
#include <iomanip>
#include <iostream>
#include <string>
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 ? "Goodn" : "Badn");
}
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;
}
不同编译器行为不同,有的判断重叠了有的没判断 https://godbolt.org/z/Er4dfPPqb
再比如STL迭代器,当然迭代器也是指针
代码语言:javascript复制erase(v, *max_element(begin(v), end(v))); //remove也有类似的问题,但是有NB说明
copy(begin(v),end(v)-1, begin(v) 1); //copy_backward补救一下,这个场景其实类似上面的重叠
auto max = ranges::max_element(a);
stable_partition(begin(a),end(a),[=](const auto&x) {return x != *max;});
除了引入bug,歧义别名问题还会引发性能问题,c里为了这个问题引入了restrict
代码语言:javascript复制void foo(std::vector<double>& v, const double& coeff) {
for (auto& item : v) item *= std::sin(coeff);
}
改成传值性能翻倍
其他的就没啥了。讲了一些标准委员会的提案,我觉得没啥说的
这个哥们讲过很多次这个问题,这次是又重新汇总了一波
- • Breaking-Dependencies-The-Visitor-Design-Pattern-Klaus-Iglberger
这哥们是 c software design的作者
对于数组多对象调用不同接口的多态模式,
std::visit std::variant相比要快一点,代码看上去也更优雅。仅作参考
- • Back-to-Basics-Value-Semantics
还是上面那个哥们
这个比较简单,举了几个引用导致错误数据的例子,然后说值语义很有用,但没人用,介绍了几个组件 optional expected之类的
- • a_pattern_language_for_expressing_concurrency
看几段代码
代码语言:javascript复制ex::sender auto schedule_request_start(read_requests_ctx ctx) { … }
ex::sender auto validate_request(const http_request& req) { … }
ex::sender auto handle_request(const http_request& req) { … }
ex::sender auto send_response(const http_response& resp) { … }
ex::sender auto request_pipeline(read_requests_ctx ctx) {
return
schedule_request_start(ctx)
| ex::let_value(validate_request)
| ex::let_value(handle_request)
| ex::let_value(send_response)
;
}
auto handle_connection(const conn_data& cdata) {
return read_http_request(cdata.io_ctx_, cdata.conn_)
| ex::transfer(cdata.pool_.get_scheduler())
| ex::let_value([&cdata](http_server::http_request req) {
return handle_request(cdata, std::move(req));
})
| ex::let_error([](std::exception_ptr) { return just_500_response(); })
| ex::let_stopped([]() { return just_500_response(); })
| ex::let_value([&cdata](http_server::http_response r) {
return write_http_response(cdata.io_ctx_, cdata.conn_, std::move(r));
});
}
auto read_http_request(io::io_context& ctx, const io::connection& conn)
-> task<http_server::http_request> {
http_server::request_parser parser;
std::string buf;
buf.reserve(1024 * 1024);
io::out_buffer out_buf{buf};
while (true) {
std::size_t n = co_await io::async_read(ctx, conn, out_buf);
auto data = std::string_view{buf.data(), n};
auto r = parser.parse_next_packet(data);
if (r)
co_return {std::move(r.value())};
}
}
auto write_http_response(io::io_context& ctx, const io::connection& conn,
http_server::http_response resp) -> task<std::size_t> {
std::vector<std::string_view> out_buffers;
http_server::to_buffers(resp, out_buffers);
std::size_t bytes_written{0};
for (auto buf : out_buffers) {
while (!buf.empty()) {
auto n = co_await io::async_write(ctx, conn, buf);
bytes_written = n;
buf = buf.substr(n);
}
}
co_return bytes_written;
}
代码语言:javascript复制
代码语言:javascript复制ex::sender auto read_from_socket() { … }
ex::sender auto process(in_data) { … }
ex::sender auto write_output(out_data) { … }
io_ontext io_threads;
static_thread_pool work_pool{8};
ex::scheduler auto sch_io = io_threads.get_scheduler();
ex::scheduler auto sch_cpu = work_pool.get_scheduler();
ex::sender auto snd
= ex::on(sch_io, read_from_socket())
| ex::transfer(sch_cpu)
| ex::let_value(process)
| ex::transfer(sch_io)
| ex::let_value(write_output)
;
sync_wait(std::move(snd));
其实这玩意类似cpptaskflow在不同的execution上调度,实际上就是换一种写法
sender就是task sender也可以是coroutine 这样所有的就都串联起来了
所谓结构化编程,抽出线程之类的粗糙底座
- • TS2 Tricks and Tips
介绍hazardptr实现的,有点意思,这个值得展开讲讲。这里标记个TODO
- • [[likely]] Optimizations, [[unlikely]] Consequences
作者压测了几个场景使用[[likely]] [[unlikely]] 没啥差别,反而影响icache
使用最好压测一下,可能和代码layout相关,导致没啥收益
- • MODERN C TO IMPRESS YOUR EMBEDDED DEV FRIENDS
嵌入式相关,一些代码优化,比较常规,比如enum class 还有上面提到的constexpr math库等等
- • Using Modern C to Revive and Old Design
讲的还是结构化编程那玩意
- • Jason-Turner-API-Design-Back-to-Basics
多用 [[nodiscard]],提示忽略的返回值
多用 noexcept 但是用了noexcept抛异常会直接挂掉
永远不要返回裸指针,起码用个not_null own_ptr之类的包装一下
错误处理,不要搞全局绕过的,比如errno get_last_error这种逼玩意
错误不是返回个错误码就完了,要必须处理,错误别optional 推荐expected
有些接口设计的语义模糊,参数可能窜位置,这种场景主要是implicit convention 隐式转换了,直接标记delete函数,规避这种场景
尽量避免传指针
fuzzer接口
尽可能constexpr
jason讲的还算有意思
- • cppcon-understanding_allocator_impact_on_runtime_performance
这个讲的不如2017年那个allocator演讲,B站搜 Local (Arena) Memory Allocators,作者john lakos 主要还是要了解pmr 里那几个allocator用途
这个演讲主要是压测了一下 monotonic_buffer_resource 配 内存块(local memory buffer)的收益
不用说你也知道比系统allocator强很多
话说 john lakos这人有点牛逼,很多书你都想象不到是他写的
有个大规模c 系统设计就是他写的,前几年重写了第二版,变成两卷,还有去年的热门书 Embracing modern c safety
今年要出一本关于allocator的书,以及大规模c 系统设计出第三卷。
看视频看多了发现牛逼的人还是比较拔尖的,比如AA还有这个john lakos,演讲多文本也多
还剩40多个没看完,下期再说
开源项目需要人手
- • asteria[11] 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
- • Unilang[12] deepin的一个通用编程语言,点子有点意思,也缺人,感兴趣的可以github讨论区或者deepin论坛看一看。这里也挂着长期推荐了
- • gcc-mcf[13] 懂的都懂
读到这里真是辛苦你了,加个额外的互动环节,最近和群友讨论了很多坑爹的c 面试题,考一些边角的c 知识,什么如何禁止new啊虚表布局啊之类的
你觉得有啥面试题是真的好的面试题,有啥面试题是垃圾面试题?欢迎投稿/评论区反馈
我之前拉了个微信群满了,再拉一个应该够了,主要是接受投稿 交流用的,感兴趣的加一下
引用链接
[1]
周刊项目地址: https://github.com/wanghenshui/cppweeklynews
[2]
提交 issue: https://github.com/wanghenshui/cppweeklynews/issues
[3]
Did you know about C 26 proposal - inplace_vector? : https://github.com/tip-of-the-week/cpp/blob/master/tips/348.md
[4]
C :constexpr的数学库: https://zhuanlan.zhihu.com/p/659750763
[5]
C :constexpr的数学库(二): https://zhuanlan.zhihu.com/p/659994358
[6]
C 成员指针完全解析(pointer to member): https://zhuanlan.zhihu.com/p/659510753
[7]
现代 C 及其在 ClickHouse 中的应用: https://zhuanlan.zhihu.com/p/655663455
[8]
C 实用技巧之 defer: https://zhuanlan.zhihu.com/p/660233833
[9]
Type Sequence and Factory Method: https://biowpn.github.io/bioweapon/2023/10/05/type-sequence-factory-pattern.html
[10]
Are Function Pointers and Virtual Functions Really Slow? : https://lucisqr.substack.com/p/are-function-pointers-and-virtual?r=1ecjkz&utm_campaign=post&utm_medium=web
[11]
asteria: https://github.com/lhmouse/asteria
[12]
Unilang: https://github.com/linuxdeepin/unilang
[13]
gcc-mcf: https://gcc-mcf.lhmouse.com/