RSS https://github.com/wanghenshui/cppweeklynews/releases.atom
欢迎投稿,推荐或自荐文章/软件/资源等,评论区留言
本期文章由 HNY 赞助
最近博客内容较少,所以基本整合起来发
资讯
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 本周更新 2024-03-20 第246期
最近的热门事件无疑是xz被植入后门了,埋木马的哥们主动参与社区贡献,骗取信任拿到直接commit权限
趁主要维护人休假期间埋木马,但是木马有问题回归测试被安全人员发现sshd CPU升高,找到xz是罪魁祸首
无间道搁这
文章
How can I tell C that I want to discard a nodiscard value? https://devblogs.microsoft.com/oldnewthing/20240329-00/?p=109592
std::ignore
或者 decltype(std::ignore) _;
然后用 _
,或者不自己写,等c 26
Step-by-Step Analysis of Crash Caused by Resize from Zero https://light-city.medium.com/step-by-step-analysis-of-crash-caused-by-resize-from-zero-30ad1562b6cc
resize 的参数为负数会异常(比如参数溢出意外负数)
有句讲句,标准库里的异常有时候很奇怪,大动干戈,副作用还是异常应该有明显的区分。但是目前来看显然是一股脑全异常了
比如stoi异常,这些场景里expect<T>
更合适,或者c传统的返回值处理更合理一些
RDMA性能优化经验浅谈(一) https://zhuanlan.zhihu.com/p/522332998
科普
GCC 14 Boasts Nice ASCII Art For Visualizing Buffer Overflows https://www.phoronix.com/news/GCC-14-fanalyzer-Enhancements
告警更明显一些
Improvements to static analysis in the GCC 14 compiler https://developers.redhat.com/articles/2024/04/03/improvements-static-analysis-gcc-14-compiler
gcc14加了个-fanalyzer
包括上面的buffer溢出分析,死循环分析,比如 https://godbolt.org/z/vn55nn43z
代码语言:javascript复制void test (int m, int n) {
float arr[m][n];
for (int i = 0; i < m; i )
for (int j = 0; j < n; i )
arr[i][j] = 0.f;
/* etc */
}
这里里面的循环条件一直没变,所以一直是死的
编译器能分析出问题
代码语言:javascript复制<source>: In function 'test':
<source>:5:23: warning: infinite loop [CWE-835] [-Wanalyzer-infinite-loop]
5 | for (int j = 0; j < n; i )
| ~~^~~
'test': events 1-5
|
| 5 | for (int j = 0; j < n; i )
| | ~~^~~ ~~~
| | | |
| | | (4) looping back...
| | (1) infinite loop here
| | (2) when 'j < n': always following 'true' branch...
| | (5) ...to here
| 6 | arr[i][j] = 0.f;
| | ~~~~~~~~~
| | |
| | (3) ...to here
|
ASM generation compiler returned: 0
<source>: In function 'test':
<source>:5:23: warning: infinite loop [CWE-835] [-Wanalyzer-infinite-loop]
5 | for (int j = 0; j < n; i )
| ~~^~~
'test': events 1-5
|
| 5 | for (int j = 0; j < n; i )
| | ~~^~~ ~~~
| | | |
| | | (4) looping back...
| | (1) infinite loop here
| | (2) when 'j < n': always following 'true' branch...
| | (5) ...to here
| 6 | arr[i][j] = 0.f;
| | ~~~~~~~~~
| | |
| | (3) ...to here
|
Execution build compiler returned: 0
Program returned: 255
这个功能非常有用 gcc14已经发布,能体验到赶紧用起来,免费的静态检查了属于是
A case in API ergonomics for ordered containers https://bannalia.blogspot.com/2024/04/a-case-in-api-ergonomics-for-ordered.html
range的问题,如果range 的顺序颠倒,可能会产生未定义行为
举个例子,正常的范围使用
代码语言:javascript复制
std::set<int> x=...;
// elements in [a,b]
auto first = x.lower_bound(a);
auto last = x.upper_bound(b);
while(first != last) std::cout<< *first <<" ";
// elements in [a,b)
auto first = x.lower_bound(a);
auto last = x.lower_bound(b);
// elements in (a,b]
auto first = x.upper_bound(a);
auto last = x.upper_bound(b);
// elements in (a,b)
auto first = x.upper_bound(a);
auto last = x.lower_bound(b);
这里的用法的潜在条件是a < b,如果不满足,就完蛋了, 似乎没有办法预防写错,手动assert?
这也容易引起错误,能不能让使用者不要用接口有隐形成本?
boost multiindex设计了一种接口
代码语言:javascript复制template<typename LowerBounder,typename UpperBounder>
std::pair<iterator,iterator>
range(LowerBounder lower, UpperBounder upper);
显然,不同的类型,隐含一层检查,看上去不好用,但是结合boost lambda2,非常直观
代码语言:javascript复制// equivalent to std::set<int>
boost::multi_index_container<int> x=...;
using namespace boost::lambda2;
// [a,b]
auto [first, last] = x.range(_1 >= a, _1 <= b);
// [a,b)
auto [first, last] = x.range(_1 >= a, _1 < b);
// (a,b]
auto [first, last] = x.range(_1 > a, _1 <= b);
// (a,b)
auto [first, last] = x.range(_1 > a, _1 < b);
代码语言:javascript复制
倾向于返回range处理,而不是手动拿到range,即使出现a>b的场景,顶多返回空range
这样要比上面的用法更安全一些
唉,API设计的问题还是有很多需要关注的地方
C left arrow operator https://www.atnnn.com/p/operator-larrow/
幽默代码一例(别这么写)
代码语言:javascript复制#include <iostream>
template<class T>
struct larrow {
larrow(T* a_) : a(a_) { }
T* a;
};
template <class T, class R>
R operator<(R (T::* f)(), larrow<T> it) {
return (it.a->*f)();
}
template<class T>
larrow<T> operator-(T& a) {
return larrow<T>(&a);
}
struct C {
void f() { std::cout << "foon"; }
};
int main() {
C x;
(&C::f)<-x;
}
Upgrading the compiler: undefined behaviour uncovered https://www.sandordargo.com/blog/2024/04/03/upgrading-the-compiler-and-undefined-behaviour
TLDR enum没指定默认值的bug,类似int不指定默认值
Trivial, but not trivially default constructible https://quuxplusone.github.io/blog/2024/04/02/trivial-but-not-default-constructible/
一个例子
代码语言:javascript复制template<class T>
struct S {
S() requires (sizeof(T) > 3) = default;
S() requires (sizeof(T) < 5) = default;
};
static_assert(std::is_trivial_v<S<int>>);
static_assert(not std::is_default_constructible_v<S<int>>);
是trivial的,但是构造函数有点多,就没法默认构造
你问这有什么用,确实没用。当不知道好了
今天也和读者聊天问push back T构造异常了咋办,
那我只能说这个T的实现很没有素质,除了bad alloc别的老子不想管
希望大家都做一个有素质的人
Understanding and implementing fixed point numbers http://www.sunshine2k.de/articles/coding/fp/sunfp.html
看不懂
Random distributions are not one-size-fits-all (part 1) https://codingnest.com/random-distributions-are-not-one-size-fits-all-part-1/
Random distributions are not one-size-fits-all (part 2) https://codingnest.com/random-distributions-are-not-one-size-fits-all-part-2/
随机数生成和场景关联程度太大了,lemire的算法省掉了取余% 但是部分场景性能并不能打败使用取余%的版本
How fast is rolling Karp-Rabin hashing? https://lemire.me/blog/2024/02/04/how-fast-is-rolling-karp-rabin-hashing/
其实就是滚动hash,比如这种
代码语言:javascript复制uint32_t hash = 0;
for (size_t i = 0; i < len; i ) {
hash = hash * B data[i];
}
return hash;
这个B可能是个质数,比如31,不过不重要
考虑一个字符串子串匹配场景,这种场景下得计算字串hash,比如长字符串内长度为N的子串,代码类似这样
代码语言:javascript复制for(size_t i = 0; i < len-N; i ) {
uint32_t hash = 0;
for(size_t j = 0; j < N; j ) {
hash = hash * B data[i j];
}
//...
}
这个代码的问题是效率低,有没有什么优化办法?
显然这里面有重复计算,到N之前的hash计算完全可以提前算出来
后面变动的减掉就行
代码语言:javascript复制uint32_t BtoN = 1;
for(size_t i = 0; i < N; i ) { BtoN *= B; }
uint32_t hash = 0;
for(size_t i = 0; i < N; i ) {
hash = hash * B data[i];
}
// ...
for(size_t i = N; i < len; i ) {
hash = hash * B data[i] - BtoN * data[i-N];
// ...
}
不知道你看懂没?
这样提前算好性能翻个五倍没啥问题
代码在这里 https://github.com/lemire/clhash/
还有这个 https://github.com/lemire/rollinghashcpp
视频
C Weekly - Ep 421 - You're Using optional, variant, pair, tuple, any, and expected Wrong! https://www.youtube.com/watch?v=0yJk5yfdih0&ab_channel=C++WeeklyWithJasonTurner
不要返回类似optional这种盒子类型,会破坏RVO
StatusOr<T>
应该也不太合适