C++ 中文周刊 第144期

周刊项目地址

公众号

qq群 点击进入

RSS https://github.com/wanghenshui/cppweeklynews/releases.atom

欢迎投稿,推荐或自荐文章/软件/资源等

提交 issue 或评论区留言

大家新年快乐

群友讨论了一个场景


#include <vector>
#include <memory_resource>
#include <iostream>
int main() {
    std::pmr::monotonic_buffer_resource pool{10000};
    std::pmr::synchronized_pool_resource pool2;
    std::pmr::vector<int> vec(5, &pool);
    static_assert(!std::allocator_traits<std::pmr::vector<int>::allocator_type>::propagate_on_container_swap::value, "is true");
    std::pmr::vector<int> vec2(4, &pool2);

    std::cout << vec.data() << " " << vec2.data() << std::endl;
    vec2.swap(vec);
    std::cout << vec.data() << " " << vec2.data() << std::endl;
    
    return 0;
}
// 0x557469f1c500 0x557469f1eea0
// 0x557469f1eea0 0x557469f1c500

地址居然是可交换的,显然这是UB

std::allocator_traits::propagate_on_container_swap::value

If std::allocator_traits::propagate_on_container_swap::value is true, then the allocators are exchanged using an unqualified call to non-member swap. Otherwise, they are not swapped (and if get_allocator() != other.get_allocator(), the behavior is undefined).

https://en.cppreference.com/w/cpp/container/vector/swap

资讯

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

编译器信息最新动态推荐关注hellogcc公众号 本周更新 2023-12-27 第234期

文章

沈芳的一波execution文章,写得不错,学吧,都是知识

还是协程,再看一遍

tag_invoke疑似有点太泛型了,作者觉得还是rust traits直观,提出了个traits object的概念

看代码 https://godbolt.org/z/Ge43cWfn8


#include <type_traits>

constexpr inline struct {
    constexpr auto eq(auto rhs, auto lhs) const {return rhs == lhs;}
    constexpr auto ne(auto rhs, auto lhs) const {return !eq(lhs, rhs);}
} partial_eq_default;

template<class T>
constexpr inline auto partial_eq = partial_eq_default;
 
template<>
constexpr inline auto partial_eq<double> = std::false_type{};

constexpr bool f(auto lhs, auto rhs) {
    return partial_eq<decltype(lhs)>.eq(lhs, rhs);
}

// bool g(double lhs, double rhs) {
//    auto& op = partial_eq<decltype(lhs)>;
//    return op.ne(lhs, rhs);
// }

constexpr bool g(int lhs, int rhs) {
    auto& op = partial_eq<int>;
    return op.ne(lhs, rhs);
}

static_assert(f('a', 'a'));
static_assert(!f('a', 'b'));
static_assert(g('a', 'b'));


int main() {
    bool b1 = f(1,2);
    bool b2 = g(1,2);
    return 0;
}

挺好的。之前132期提到定制log就是类似的技术

namespace logging {
namespace null {
struct config {
    struct {
        template <level L, typename... Ts>
        // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
        constexpr auto log(Ts &&...) const noexcept -> void {}
    } logger;
};
} // namespace null

template <typename...> inline auto config = null::config{};

template <level L, typename... Ts, typename... TArgs>
static auto log(TArgs &&...args) -> void {
    auto &cfg = config<Ts...>;
    cfg.logger.template log<L>(std::forward<TArgs>(args)...);
}
}

#include <meta>

int main() {
    struct foo {};
    std::cout << std::meta::name_of(^foo); // prints foo
}

没啥说的

众所周知,static局部对象只初始化一次


struct ExpensiveInitialization {
    ExpensiveInitialization() noexcept;
    void DoWork() noexcept;
};

void DoWork() noexcept {
    static ExpensiveInitialization expensive;
    expensive.DoWork();
}

但如果DoWork或者ExpensiveInitialization变成模版函数,是不是意味着 static每个函数都构建一次?破坏了语义?

作者提出了一种模版特化校验的方法


#include <type_traits>

template<bool const* p, typename SLOC>
struct assert_single_instantiation final {
	friend consteval std::integral_constant<bool const*, p> detect_multiple_instances(SLOC) {
        return {};
    }
};

#define ASSERT_SINGLE_INSTANTIATION \
	{ \
		static constexpr bool _b = false; \
		[](auto sloc) noexcept { \
			[[maybe_unused]] assert_single_instantiation<&_b, decltype(sloc)> _; \
		}(std::integral_constant<int, __COUNTER__>()); \
	}

#define singleton_static ASSERT_SINGLE_INSTANTIATION; static

struct ExpensiveInitialization {
    ExpensiveInitialization() noexcept;
    void DoWork() noexcept;
};

void DoWork() noexcept {
    singleton_static ExpensiveInitialization expensive;
    expensive.DoWork();
}

没有任何额外开销 https://godbolt.org/z/hcEWeqf6P

就是我没看明白怎么用的

raymond chen windows环节

视频

My favourite memory leak - Björn Fahller - Lightning Talks @ Meeting C++ 2023

一段会泄漏内存的抽象代码

#include <vector>

struct V : std::vector<V> {}

int main() {
  V v;
  v.emplack_back();
  v.swap(v.front());
}

非常幽默

众所周知,vector是三个指针,begin end storend三部分,swap交换自己的时候,这三个指针怎么赋值?

当然,写成c就更容易懂了 (感谢群友@只看封面)

V相当于 class V { V* data;}

Implementing coroutines using C++17 - Alon Wolf - Lightning Talks @ Meeting C++ 2023

看不太懂,也没放源代码。感觉是用intel的jmp汇编和goto搞跳转

开源项目

工作招聘

字节的音视频团队,主要负责剪映上的音视频/非线性编辑相关工作,业务前景也比较好,目前有三个方向的岗位

base北上广深杭都可以,薪资open,有兴趣的同学可以通过链接投递

互动环节

大家新年快乐,祝大家健康!散会!


本文永久链接

如果有疑问评论最好在上面链接到评论区里评论,这样方便搜索,微信公众号有点封闭/知乎吞评论

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持! 觉得写的不错那就给点吧, 在线乞讨 微信转账