文章
https://www.tonni.nl/blog/shared-ptr-overuse-cpp
省流 不共享不要滥用
https://purplesyringa.moe/blog/falsehoods-programmers-believe-about-null-pointers/
列举一些对空指针的误解,比如访问空指针会挂,c/c++语言设定如此,其他语言会捕获异常特殊处理
额我觉得还是不要知道的好
https://www.sandordargo.com/blog/2025/02/05/cpp26-erroneous-behaviour
c++的未定义行为涉及的面太广,有必要收敛一些场景,比如没有初始化读就读这种场景,归纳为EB
如果真的需要这种行为,主动标记[[indeterminiate]] 这种标记下没初始化就使用才被归纳为UB
比如
void foo() {
int d [[indeterminate]]; // d has an indeterminate value
bar(d); // that's undefined behaviour!
}
不过目前为止只是提案 P2795,没有编译器支持实现
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2795r5.html
https://lemire.me/blog/2025/02/07/thread-safe-memory-copy/
https://github.com/v8/v8/blob/9e5d8118e2af44b94515db813f5a0aecd8149b7a/src/base/atomicops.h#L363
inline void Relaxed_Memcpy(volatile Atomic8* dst, volatile const Atomic8* src,
size_t bytes) {
constexprsize_t kAtomicWordSize = sizeof(AtomicWord);
while (bytes > 0 &&
!IsAligned(reinterpret_cast<uintptr_t>(dst), kAtomicWordSize)) {
Relaxed_Store(dst++, Relaxed_Load(src++));
--bytes;
}
if (IsAligned(reinterpret_cast<uintptr_t>(src), kAtomicWordSize) &&
IsAligned(reinterpret_cast<uintptr_t>(dst), kAtomicWordSize)) {
while (bytes >= kAtomicWordSize) {
Relaxed_Store(
reinterpret_cast<volatile AtomicWord*>(dst),
Relaxed_Load(reinterpret_cast<constvolatile AtomicWord*>(src)));
dst += kAtomicWordSize;
src += kAtomicWordSize;
bytes -= kAtomicWordSize;
}
}
while (bytes > 0) {
Relaxed_Store(dst++, Relaxed_Load(src++));
--bytes;
}
}
每个byte都原子store load 线程安全了
对于V8来说,安全比较重要。即使这玩意慢三四十倍
省流 shared ptr一律使用make_shared构造
使用alias 构造 搭配weak ptr使用存在问题
如何避免类只能通过make_shared构造?构造函数tag + 静态函数匹配。看嗲吗
class A: std::enable_shared_from_this<A> {
private:
struct Private {};
public:
A(Private dummy, int member) : member_(member) {}
template <typename... ArgsT>
static std::shared_ptr<A> create(ArgsT&&... args) {
returnstd::make_shared<A>(Private(), std::forward<ArgsT>(args)...);
}
private:
int member_ = 1;
};
int main() {
std::cout << "The Start\n\n";
auto a_sptr = A::create(42);
std::cout << std::endl << "The End!";
return0;
}
https://docs.google.com/presentation/d/1PbCH2IRg8lW08JlUz-xQEQjTo_Fr5n9QZOTEjGqZnuU/edit#slide=id.g1e93a5b7c98_0_172
介绍数据局部性有利的数据结构 Dense/Sparse Array
简单说就是这个德行
#include <vector>
#include <cassert>
template<typename T>
class DenseSparseArray {
public:
// 插入元素(假设 entity 是唯一标识)
void insert(uint32_t entity, const T& value) {
if (entity >= sparse.size()) {
sparse.resize(entity + 1, -1); // -1 表示无效索引
}
if (sparse[entity] == -1) {
sparse[entity] = dense.size();
dense.push_back({entity, value});
}
}
// 删除元素
void erase(uint32_t entity) {
if (contains(entity)) {
size_t dense_idx = sparse[entity];
auto& last = dense.back();
// 将要删除的元素与最后一个元素交换
std::swap(dense[dense_idx], last);
sparse[last.entity] = dense_idx;
dense.pop_back();
sparse[entity] = -1;
}
}
// 访问元素
T& operator[](uint32_t entity) {
assert(contains(entity));
return dense[sparse[entity]].value;
}
// 判断是否存在
bool contains(uint32_t entity) const {
return entity < sparse.size() && sparse[entity] != -1;
}
// 迭代器支持
auto begin() { return dense.begin(); }
auto end() { return dense.end(); }
private:
struct Element {
uint32_t entity;
T value;
};
std::vector<int> sparse; // 稀疏数组(存储索引)
std::vector<Element> dense; // 密集数组(实际数据)
};
enseSparseArray<int> arr;
arr.insert(100, 42); // 插入 entity=100
arr.insert(200, 77); // 插入 entity=200
std::cout << arr[100]; // 输出 42
arr.erase(100); // 删除 entity=100
for (auto& elem : arr) { // 遍历所有有效元素
std::cout << elem.entity << ": " << elem.value << "\n";
}
deepseek帮我写的
这种玩法比较方便遍历且不失访问速度,对于小数据集是非常有用的
另外PPT里还提到了一些优化。感兴趣可以看EnTT代码
https://github.com/skypjack/entt
https://meetingcpp.com/mcpp/slides/2023/Mulithreading_performance735913.pdf
简单介绍MESI那套东西,多线程 cache局部性非常重要,另外介绍一些影响性能的场景
https://meetingcpp.com/mcpp/slides/2023/Class%20Layout%20-%20meeting%20c++271911.pdf
比较常规
介绍了基本的字段大小,继承影响,对齐影响,EBO,no_unique_address, 以及分析工具
clang++ -cc1 -fdump-record-layouts # (or -Xclang -fdump-record-layouts)
g++ -fdump-lang-class (or -fdump-class-hierarchy) # (dumps to a file, so not usable in Compiler explorer)
msvc /d1reportAllClassLayout