标准委员会动态/ide/编译器信息放在这里
十二月邮件列表[1]
[编译器信息最新动态推荐关注hellogcc公众号 本周更新 2024-01-04 第286期](OSDT Weekly 2024-12-25 第286期 )
google在 c++安全上的实践,主要是采用libc++ harden mode
非常推荐使用。我之前搞了个安全的介绍,感兴趣可以看一下 [3]
支持字段级别设置attr了 p0609[5]
auto [it, inserted [[maybe_unused]] ] = map.try_emplace(key, value);
支持在条件中展开,类似c++17那个条件中赋值
if (auto[n]=f()){...}
while(auto[header, body]=receive_packet()){...}
展开绑定到tuple p1061[6]
template <class T>
auto tie_as_tuple(T& x) {
auto& [...xs] = x;
return std::tie(xs...);
}
如果这个能支持,真是有点改变相关工具生态了 magic get/boost pfr可是做了好多脏活[7]
介绍hash combine和 tie组合的。
#include <string>
#include <tuple>
#include <cassert>
#include <cstdint>
#include <boost/functional/hash.hpp>
#include <iostream>
namespace some_lib {
template<typename T>
constexpr void hash_combine(size_t& seed, const T& value)
{
seed ^= std::hash<T>{}(value)+0x9e3779b9+(seed <<6)+(seed >>2);
}
}
template<typename...TValues>
constexpr auto combined_hash(const TValues&... values)
{
size_t seed{};
(..., some_lib::hash_combine(seed, values));
return seed;
}
structHashableForTiedMembers
{};
template<typename T>
constexprbool hashing_for_tied_members =false;
template<typename T>
conceptHashableForTied= std::derived_from<T,HashableForTiedMembers>|| hashing_for_tied_members<T>;
template<HashableForTied T>
structstd::hash<T>
{
size_t operator()(const T& value) const
{
auto hasher =[](constauto&... args){
returncombined_hash(args...);
};
return std::apply(hasher, value.tied());
}
};
template<typename T>
conceptHashable=requires{
{ std::hash<T>{}(std::declval<T>())}-> std::convertible_to<size_t>;
};
/////////////////////////////////////////////////////////////////////////
// Person class - opt-in through inheritance
structPerson:HashableForTiedMembers
{
std::string first_name;
std::string last_name;
std::uint8_t age;
Person(std::string first_name, std::string last_name, std::uint8_t age)
: first_name{std::move(first_name)}
, last_name{std::move(last_name)}
, age{age}
{
}
auto tied() const
{
return std::tie(first_name, last_name, age);
}
booloperator==(constPerson& other)const
{
returntied()== other.tied();
}
autooperator<=>(constPerson& other)const
{
returntied()== other.tied();
}
};
static_assert(Hashable<Person>);
//////////////////////////////////////////////////////////////////////////
// AggregatePerson - opt-in through variable template specialization
structAggregatePerson
{
std::string first_name;
std::string last_name;
std::uint8_t age;
auto tied() const
{
return std::tie(first_name, last_name, age);
}
};
template<>
constexprbool hashing_for_tied_members<AggregatePerson>=true;
int main()
{
Person p1{"John","Doe",33};
Person p2{"John","Doe",33};
Person p3{"John","Don",44};
assert(p1 == p2);
assert(p2 < p3);
assert(std::hash<Person>{}(p1)== std::hash<Person>{}(p2));
assert(std::hash<Person>{}(p1)== std::hash<Person>{}(p3));
AggregatePerson ap1{"John","Doe",30};
AggregatePerson ap2{"John","Doe",30};
AggregatePerson ap3{"John","Dog",30};
assert(std::hash<AggregatePerson>{}(ap1)== std::hash<AggregatePerson>{}(ap2));
assert(std::hash<AggregatePerson>{}(ap1)!= std::hash<AggregatePerson>{}(ap3));
return std::hash<Person>{}(p1);
}
其实他这个设计就是hash_append
template <class HashAlgorithm>
friend void hash_append(HashAlgorithm& h, X const& x) noexcept
{
//
}
他这个写法就是把hash算法和x拆出来,x本身转pack 方便归一计算,用的tie 避免开销
combined_hash其实就是hash_append 只不过算法h不能定制
不知道读者们了不了解n3980 hash_append 不了解没关系。就是函数接口定制和这里的代码一个意思
非常搞笑的场景,同样的hashmap float 做key和 int做key冲突率不同 因为值域不同。float表达式导致的
针对float做key要注意hash算法
和shared_ptr差不多,为了原子 使用tag pointer 用特殊字段做spinlock 代码在这里[11]
while (!_M_val.compare_exchange_strong(__current,
__current | _S_lock_bit,
__o,
memory_order_relaxed))
{
_GLIBCXX_TSAN_MUTEX_TRY_LOCK_FAILED(&_M_val);
#if __glibcxx_atomic_wait
__detail::__thread_relax();
#endif
__current = __current &~_S_lock_bit;
_GLIBCXX_TSAN_MUTEX_TRY_LOCK(&_M_val);
}
_GLIBCXX_TSAN_MUTEX_LOCKED(&_M_val);
returnreinterpret_cast<pointer>(__current);
}
直接贴代码
#include <bitset>
#include <ostream>
#include <type_traits>
#include <utility>
// Helper class for bitwise flag-like operations on scoped enums.
//
// This class provides a way to represent combinations of enum values without
// directly overloading operators on the enum type itself. This approach
// avoids ambiguity in the type system and allows the enum type to continue
// representing a single value, while the BitFlags can hold a combination
// of enum values.
//
// Example usage:
//
// enum class MyEnum { FlagA = 1 << 0, FlagB = 1 << 1, FlagC = 1 << 2 };
//
// BitFlags<MyEnum> flags = { MyEnum::FlagA, MyEnum::FlagC };
// flags.Unset(MyEnum::FlagA);
// if (flags.IsSet(MyEnum::FlagC)) {
// // ...
// }
//
// flags |= MyEnum::FlagB;
// BitFlags<MyEnum> new_flags = ~flags;
template<typename T>
classBitFlags{
usingUnderlyingT= std::underlying_type_t<T>;
public:
constexpr BitFlags() : flags_(static_cast<UnderlyingT>(0)) {}
constexpr explicit BitFlags(T v) : flags_(ToUnderlying(v)) {}
constexpr BitFlags(std::initializer_list<T> vs) : BitFlags() {
for(T v : vs){
flags_ |=ToUnderlying(v);
}
}
// Checks if a specific flag is set.
constexpr bool IsSet(T v) const {
return(flags_ &ToUnderlying(v))==ToUnderlying(v);
}
// Sets a single flag value.
constexpr void Set(T v) { flags_ |=ToUnderlying(v);}
// Unsets a single flag value.
constexpr void Unset(T v) { flags_ &=~ToUnderlying(v);}
// Clears all flag values.
constexpr void Clear() { flags_ =static_cast<UnderlyingT>(0);}
constexpr operator bool() const {
return flags_ !=static_cast<UnderlyingT>(0);
}
friendconstexprBitFlagsoperator|(BitFlags lhs, T rhs){
returnBitFlags(lhs.flags_ |ToUnderlying(rhs));
}
friendconstexprBitFlagsoperator|(BitFlags lhs,BitFlags rhs){
returnBitFlags(lhs.flags_ | rhs.flags_);
}
friendconstexprBitFlagsoperator&(BitFlags lhs, T rhs){
returnBitFlags(lhs.flags_ &ToUnderlying(rhs));
}
friendconstexprBitFlagsoperator&(BitFlags lhs,BitFlags rhs){
returnBitFlags(lhs.flags_ & rhs.flags_);
}
friendconstexprBitFlagsoperator^(BitFlags lhs, T rhs){
returnBitFlags(lhs.flags_ ^ToUnderlying(rhs));
}
friendconstexprBitFlagsoperator^(BitFlags lhs,BitFlags rhs){
returnBitFlags(lhs.flags_ ^ rhs.flags_);
}
friendconstexprBitFlags&operator|=(BitFlags& lhs, T rhs){
lhs.flags_ |=ToUnderlying(rhs);
return lhs;
}
friendconstexprBitFlags&operator|=(BitFlags& lhs,BitFlags rhs){
lhs.flags_ |= rhs.flags_;
return lhs;
}
friendconstexprBitFlags&operator&=(BitFlags& lhs, T rhs){
lhs.flags_ &=ToUnderlying(rhs);
return lhs;
}
friendconstexprBitFlags&operator&=(BitFlags& lhs,BitFlags rhs){
lhs.flags_ &= rhs.flags_;
return lhs;
}
friendconstexprBitFlags&operator^=(BitFlags& lhs, T rhs){
lhs.flags_ ^=ToUnderlying(rhs);
return lhs;
}
friendconstexprBitFlags&operator^=(BitFlags& lhs,BitFlags rhs){
lhs.flags_ ^= rhs.flags_;
return lhs;
}
friendconstexprBitFlagsoperator~(constBitFlags& bf){
returnBitFlags(~bf.flags_);
}
friendconstexprbooloperator==(constBitFlags& lhs,constBitFlags& rhs){
return lhs.flags_ == rhs.flags_;
}
friendconstexprbooloperator!=(constBitFlags& lhs,constBitFlags& rhs){
return lhs.flags_ != rhs.flags_;
}
// Stream output operator for debugging.
friend std::ostream&operator<<(std::ostream& os,constBitFlags& bf){
// Write out a bitset representation.
os << std::bitset<sizeof(UnderlyingT)*8>(bf.flags_);
return os;
}
// Construct BitFlags from raw values.
static constexpr BitFlags FromRaw(UnderlyingT flags) {
returnBitFlags(flags);
}
// Retrieve the raw underlying flags.
constexpr UnderlyingT ToRaw() const {return flags_;}
private:
constexpr explicit BitFlags(UnderlyingT flags) : flags_(flags) {}
static constexpr UnderlyingT ToUnderlying(T v) {returnstatic_cast<UnderlyingT>(v);}
UnderlyingT flags_;
};
template<typename...Args>
structmaker
{
std::tuple<Args&&...> m_args;
maker(Args&&... args):m_args((Args&&)args...){}
template<typename T>
operator T() {
return std::make_from_tuple<T>(std::move(m_args));
}
};
template<typename D>
structOwnerHelper
{
template<typename...Args>
auto Owned(Args&&... args)
{returnmaker<Args&&..., D*>((Args&&)args...,static_cast<D*>(this));}
};
structWidget:Object,OwnerHelper<Widget>
{
Property<int>Height=Owned("Height",10);
Property<std::string>Name=Owned("Name",""s);
Event<NameChangedHandler>NameChanged=Owned("NameChanged");
};
通过crtp绕一下传this 当然如果有deducing this可以这样
struct OwnerHelper
{
template<typename O, typename...Args>
auto Owned(this O&& self, Args&&... args)
{
returnmaker<Args&&..., O*>((Args&&)args...,&self);
}
};
structWidget:Object,OwnerHelper
{
Property<int>Height=Owned("Height",10);
Property<std::string>Name=Owned("Name",""s);
Event<NameChangedHandler>NameChanged=Owned("NameChanged");
};
列举几个经典bug代码
realloc失败
int sceNetAdhocMatchingSetHelloOpt(int matchingId,
int optLenAddr, u32 optDataAddr)
{
....
if (optLenAddr > context->hellolen)
{
hello = realloc(hello, optLenAddr);
}
....
}
这里realloc失败返回null正好给hello覆盖了。原来的hello泄漏
拼写错误一个例子
static const TypeToNameMap& get_type_to_name_tbl() {
staticconstTypeToNameMap type_to_name_tbl ={
....,
{"Abs",Type::Eltwise},// <=
....,
{"SoftPlus",Type::Eltwise},// <=
....,
{"Abs",Type::Math},// <=
....,
{"SoftPlus",Type::Math},// <=
....,
};
return type_to_name_tbl;
}
继承忘记final导致误用,代码不列了有点蠢
死代码/复制粘贴错误也不列了
ifelse匹配
const qdGameObjectStateWalk* qdGameObjectMoving::current_walk_state() const
{
const qdGameObjectState* st =get_cur_state();
if(!st || st ->state_type()!= qdGameObjectState::STATE_WALK){
#ifndef _QUEST_EDITOR
st = last_walk_state_;
if(!st || st ->state_type()!= qdGameObjectState::STATE_WALK)
st =get_default_state();
else
st =get_default_state();
if(!st) st =get_state(0);
#endif
}
....
}
else忘记写#了。
不可见字符
static constchar*script_list[][2]={
....
{"Myanmar / Burmese","Mymr"},
{"Nag Mundari","Nagm"},
{"Nandinagari","Nand"},
....
}
以及数组溢出,代码不列了
本期更新距离上一期差了一个月,作者沉迷街霸是原因之一
另外的原因就是,感觉很累,有一点重复自己。在自媒体的内容想想搞一点突破,涨涨流量
但是比起去年接到商单,今年只接到图书推广单子,赠书,书我转手送了
比较惨淡
考虑了带货,带货金额没有押金多
另外就是蹭热度/日更段子阅读量更好。而周更内容实际上比较一般
确实迷茫了。反复重复自我,还是深耕一下,只讲专题,周刊改成月刊形式?
资料是看不完的,周刊总感觉只是泛泛而谈没啥深度内容
一方面,读者需要深度内容,一方面读者也看tips之类的知识点
我感觉我有点搞不过来,时间真不够用
欢迎大家提出建议意见
[1]
十二月邮件列表: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/index.html#mailing2024-12
[2]
Retrofitting spatial safety to hundreds of millions of lines of C++ : https://security.googleblog.com/2024/11/retrofitting-spatial-safety-to-hundreds.html
[3]
非常推荐使用。我之前搞了个安全的介绍,感兴趣可以看一下 : https://wanghenshui.github.io/my-slides/week2
[4]
Structured Binding Upgrades in C++26: https://biowpn.github.io/bioweapon/2024/12/03/structured-bindings-cpp26.html
[5]
p0609: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p0609r3.pdf
[6]
p1061: https://isocpp.org/files/papers/P1061R10.html
[7]
magic get/boost pfr可是做了好多脏活: https://github.com/boostorg/pfr/blob/develop/include/boost/pfr/detail/core17_generated.hpp
[8]
How to Hash Objects Without Repetition: std::hash can be DRY: https://blog.infotraining.pl/how-to-hash-objects-without-repetition
[9]
Measuring std::unordered_map Badness: https://artificial-mind.net/blog/2021/10/09/unordered-map-badness
[10]
Inside STL: The atomic shared_ptr: https://devblogs.microsoft.com/oldnewthing/20241219-00/?p=110663
[11]
代码在这里: https://github.com/gcc-mirror/gcc/blob/dc01f249db5c4d08b76dc2783b1539290a800f2d/libstdc%2B%2B-v3/include/bits/shared_ptr_atomic.h#L455
[12]
Type-safe Enum Class Bit Flags: https://voithos.io/articles/type-safe-enum-class-bit-flags/
[13]
In C++, how can I make a default parameter be the this pointer of the caller?, revisited: https://devblogs.microsoft.com/oldnewthing/20241122-00/?p=110560
[14]
Court is in session: Top 10 most notorious C and C++ errors in 2024: https://pvs-studio.com/en/blog/posts/cpp/1208/
[15]
asteria: https://github.com/lhmouse/asteria
[16]
struct to tuple : https://github.com/Rhidian12/StructToTuple/tree/main
[17]
boost更新主要加了个parser: https://www.boost.org/doc/libs/1_87_0/doc/html/parser.html