本篇介绍几个细琐的小特性,可以使代码更加安全可靠。
最常见的情况是采取 for loop 遍历某个容器,比如:
std::vectorv(10); std::iota(v,0); for(inti=v.size()-1;i>=0;--i){ std::cout<< v[i] << ' '; }
乍看之下,似乎并无问题,但实际上却存在安全隐患,若是 v.size() 的结果大于 std::numeric_limits
倘若你使用了类型推导,问题会更加明显。
for(autoi=v.size()-1;i>=0;--i){ std::cout<< v[i] << ' '; }
这会输出超出预期的结果!i 被推导为 unsigned 整型,i >= 0 将永远为真。
这种隐患来自于类型的隐式转换,一般编译器只会给出警告。最简单的解决之法就是保证整型符号的一致性,例如:
for(size_ti=v.size()-1;i< v.size(); --i) { std::cout << v[i] << ' '; }
结束条件也随之变为检测数据范围,以避免条件在逻辑上的无效性。但如此一来,可读性直线降低,C++20 引入了几个与此相关的小特性,可以更安全地解决该问题。
第一个是一系列整型比较函数,它们可以安全地对不同符号的类型进行比较。如:
-1>0u;//true std::cmp_greater(-1,0u);//false
因此,可以用来安全地比较不同符号的整型。
for(inti=0;std::cmp_less(i,v.size());++i){ std::cout<< i << " " << v[i] << ' '; }
通过使用这些安全的比较函数,代码隐患随之消除。只是无法逆序遍历了,逆序时将 size_t 赋值到 int 依旧有可能产生 UB。
此种情境,更好的方式是采用 std::ssize(),它是一个有符号的 size() 辅助函数,表意更加直接。代码更改为:
for(inti=ssize(v)-1;i>=0;--i){ std::cout<< v[i] << ' '; }
得益于 ADL,std::ssize() 可以简写为 ssize()。
当然,以上只是示例需要,对于数据遍历,Range-based for loop 是更好的方式,这样能够避免很多易被忽视的错误。
for(constauto&elem:v){ std::cout<< elem << ' '; }
通过 C++20 Views,还可以在遍历时组合其他操作,如:
for(constauto&elem:v|std::reverse){ std::cout<< elem << ' '; }
这是可读性最强的方式。
当然,还有许多其他方法,比如迭代器、算法和一些技巧,但在范式上来说,那些方法很难比这里展示的方式更加简洁,就使用来说,记住这里提到的便已足够。
推荐阅读点击标题可跳转
1、深入浅出 C++ 类型擦除
2、性能大杀器:c++中的copy elision
3、Configuring Transitive Dependencies with Modern CMake
-
函数
+关注
关注
3文章
4299浏览量
62374 -
C++
+关注
关注
21文章
2104浏览量
73469
发布评论请先 登录
相关推荐
评论