首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C++ 中文周刊 2024-12-29 第174期

C++ 中文周刊 2024-12-29 第174期

作者头像
王很水
发布2024-12-30 13:20:31
发布2024-12-30 13:20:31
14300
代码可运行
举报
运行总次数:0
代码可运行

资讯

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

十二月邮件列表[1]

[编译器信息最新动态推荐关注hellogcc公众号 本周更新 2024-01-04 第286期](OSDT Weekly 2024-12-25 第286期 )

文章

Retrofitting spatial safety to hundreds of millions of lines of C++ [2]

google在 c++安全上的实践,主要是采用libc++ harden mode

非常推荐使用。我之前搞了个安全的介绍,感兴趣可以看一下 [3]

Structured Binding Upgrades in C++26[4]

支持字段级别设置attr了 p0609[5]

代码语言:javascript
代码运行次数:0
运行
复制
auto [it, inserted [[maybe_unused]] ] = map.try_emplace(key, value);

支持在条件中展开,类似c++17那个条件中赋值

代码语言:javascript
代码运行次数:0
运行
复制
if (auto[n]=f()){...}

while(auto[header, body]=receive_packet()){...}

展开绑定到tuple p1061[6]

代码语言:javascript
代码运行次数:0
运行
复制
template <class T>
auto tie_as_tuple(T& x) {
    auto& [...xs] = x;
    return std::tie(xs...);
}

如果这个能支持,真是有点改变相关工具生态了 magic get/boost pfr可是做了好多脏活[7]

How to Hash Objects Without Repetition: std::hash can be DRY[8]

介绍hash combine和 tie组合的。

代码语言:javascript
代码运行次数:0
运行
复制
#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

代码语言:javascript
代码运行次数:0
运行
复制
    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 不了解没关系。就是函数接口定制和这里的代码一个意思

Measuring std::unordered_map Badness[9]

非常搞笑的场景,同样的hashmap float 做key和 int做key冲突率不同 因为值域不同。float表达式导致的

针对float做key要注意hash算法

Inside STL: The atomic shared_ptr[10]

和shared_ptr差不多,为了原子 使用tag pointer 用特殊字段做spinlock 代码在这里[11]

代码语言:javascript
代码运行次数:0
运行
复制
      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);
    }

Type-safe Enum Class Bit Flags[12]

直接贴代码

代码语言:javascript
代码运行次数:0
运行
复制
#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_;
};

In C++, how can I make a default parameter be the this pointer of the caller?, revisited[13]

代码语言:javascript
代码运行次数:0
运行
复制
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可以这样

代码语言:javascript
代码运行次数:0
运行
复制
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");
};

Court is in session: Top 10 most notorious C and C++ errors in 2024[14]

列举几个经典bug代码

realloc失败

代码语言:javascript
代码运行次数:0
运行
复制
int sceNetAdhocMatchingSetHelloOpt(int matchingId,
                                   int optLenAddr, u32 optDataAddr)
{
  ....
  if (optLenAddr > context->hellolen)
  {
    hello = realloc(hello, optLenAddr);
  }
  ....
}

这里realloc失败返回null正好给hello覆盖了。原来的hello泄漏

拼写错误一个例子

代码语言:javascript
代码运行次数:0
运行
复制
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匹配

代码语言:javascript
代码运行次数:0
运行
复制
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忘记写#了。

不可见字符

代码语言:javascript
代码运行次数:0
运行
复制
static constchar*script_list[][2]={
....
{"Myanmar / Burmese","Mymr"},
{"Nag Mundari","Nagm"},
{"Nandinagari","Nand"},
....
}

以及数组溢出,代码不列了

开源项目介绍

  • • asteria[15] 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群753302367和作者对线
  • • 另外 ykiko的clice也在找人,项目很有意思 https://zhuanlan.zhihu.com/p/13394352064
  • • struct to tuple [16]
  • • https://github.com/oschonrock/binfuse c++ library for binary fuse filters, including a sharded filter
  • • boost更新主要加了个parser[17] spirit有点难用

互动环节

本期更新距离上一期差了一个月,作者沉迷街霸是原因之一

另外的原因就是,感觉很累,有一点重复自己。在自媒体的内容想想搞一点突破,涨涨流量

但是比起去年接到商单,今年只接到图书推广单子,赠书,书我转手送了

比较惨淡

考虑了带货,带货金额没有押金多

另外就是蹭热度/日更段子阅读量更好。而周更内容实际上比较一般

确实迷茫了。反复重复自我,还是深耕一下,只讲专题,周刊改成月刊形式?

资料是看不完的,周刊总感觉只是泛泛而谈没啥深度内容

一方面,读者需要深度内容,一方面读者也看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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-12-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CPP每周推送 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 资讯
  • 文章
    • Retrofitting spatial safety to hundreds of millions of lines of C++ [2]
    • Structured Binding Upgrades in C++26[4]
    • How to Hash Objects Without Repetition: std::hash can be DRY[8]
    • Measuring std::unordered_map Badness[9]
    • Inside STL: The atomic shared_ptr[10]
    • Type-safe Enum Class Bit Flags[12]
    • In C++, how can I make a default parameter be the this pointer of the caller?, revisited[13]
    • Court is in session: Top 10 most notorious C and C++ errors in 2024[14]
  • 开源项目介绍
  • 互动环节
    • 引用链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档