Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
---

<!-- COVERAGE_START -->
![English Coverage](https://img.shields.io/badge/en_coverage-92%25-green.svg) 544/592 docs translated
![English Coverage](https://img.shields.io/badge/en_coverage-99%25-green.svg) 586/592 docs translated
<!-- COVERAGE_END -->

## 这是什么项目
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// 侵入式引用计数:RefCountedThreadSafe + scoped_refptr
// 来源:WeakPtr 前置知识(一):侵入式引用计数与 scoped_refptr (pre-01)
// 编译:g++ -std=c++17 -Wall -Wextra 12_intrusive_refcount.cpp -o 12_intrusive_refcount -pthread

#include <atomic>
#include <cassert>
#include <iostream>
#include <memory>

namespace {

// 跨序列安全的侵入式引用计数基类(简化版 base::RefCountedThreadSafe)
class RefCountedThreadSafe {
public:
void add_ref() const noexcept { ref_count_.fetch_add(1, std::memory_order_relaxed); }
bool release() const noexcept {
// acq_rel:减法读到最新 count;归零时把"析构前的写"发布给接管 delete 的线程
if (ref_count_.fetch_sub(1, std::memory_order_acq_rel) == 1) {
return true; // 调用方负责 delete this
}
return false;
}
bool has_one_ref() const noexcept { return ref_count_.load(std::memory_order_acquire) == 1; }
int use_count() const noexcept { return ref_count_.load(std::memory_order_acquire); }

protected:
RefCountedThreadSafe() = default;
~RefCountedThreadSafe() = default;

private:
mutable std::atomic<int> ref_count_{0};
};

// 侵入式智能指针外壳(简化版 base::scoped_refptr)
template <typename T> class scoped_refptr {
public:
scoped_refptr() noexcept = default;
explicit scoped_refptr(T* p) noexcept : ptr_(p) {
if (ptr_)
ptr_->add_ref();
}
scoped_refptr(const scoped_refptr& o) noexcept : ptr_(o.ptr_) {
if (ptr_)
ptr_->add_ref();
}
scoped_refptr(scoped_refptr&& o) noexcept : ptr_(o.ptr_) { o.ptr_ = nullptr; }
~scoped_refptr() {
if (ptr_ && ptr_->release())
delete ptr_;
}
scoped_refptr& operator=(scoped_refptr r) noexcept {
T* t = ptr_;
ptr_ = r.ptr_;
r.ptr_ = t; // copy-and-swap
return *this;
}
T* get() const noexcept { return ptr_; }
T& operator*() const noexcept { return *ptr_; }
T* operator->() const noexcept { return ptr_; }
explicit operator bool() const noexcept { return ptr_ != nullptr; }

private:
T* ptr_ = nullptr;
};

// 一个被引用计数的目标类型(析构 private,堵外部直接 delete)
class Flag : public RefCountedThreadSafe {
public:
Flag() = default;
int id() const { return id_; }

private:
// 允许 scoped_refptr 在计数归零时 delete(Chromium 式受控析构)
template <typename> friend class scoped_refptr;
~Flag() = default;
int id_ = 42;
};

scoped_refptr<Flag> make_flag() {
return scoped_refptr<Flag>(new Flag());
}

} // namespace

int main() {
std::cout << "=== 侵入式引用计数 ===\n";

auto p = make_flag(); // ref_count = 1
std::cout << " create: use_count=" << p->use_count()
<< ", has_one_ref=" << p->has_one_ref() << "\n";

{
auto p2 = p; // copy → add_ref → ref_count = 2
std::cout << " copy p2: use_count=" << p2->use_count()
<< ", has_one_ref=" << p2->has_one_ref() << "\n";
} // p2 析构 → release → ref_count = 1(不 delete)
std::cout << " p2 gone: use_count=" << p->use_count() << "\n";

{
auto p3 = std::move(p); // move → 不增不减,p 变空
std::cout << " move to p3: p valid=" << (p ? "yes" : "no")
<< ", p3 use_count=" << p3->use_count() << "\n";
} // p3 析构 → release → ref_count = 0 → delete

std::cout << "\n=== 与 std::shared_ptr 的分配/大小对比 ===\n";
// shared_ptr 非侵入式:控制块是独立堆分配(与对象分开);scoped_refptr 侵入式:计数器是对象成员
struct Pod {
int x;
}; // 用一个平凡类型做 sizeof 对比(Flag 析构 private 不便塞 shared_ptr)
std::cout << " sizeof(scoped_refptr<Pod>) = " << sizeof(scoped_refptr<Pod>)
<< " (1 个指针)\n";
std::cout << " sizeof(std::shared_ptr<Pod>) = " << sizeof(std::shared_ptr<Pod>)
<< " (2 个指针:对象 + 控制块)\n";
std::cout << " 分配:shared_ptr<Pod>(new Pod) 2 次;make_shared 1 次但捆死内存;scoped_refptr 1 "
"次(计数嵌入对象)\n";
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// AtomicFlag:一次性、release-Set / acquire-IsSet 的原子标志
// 来源:WeakPtr 前置知识(二):std::atomic 与 memory_order (pre-02)
// 编译:g++ -std=c++17 -Wall -Wextra 13_atomic_flag.cpp -o 13_atomic_flag -pthread

#include <atomic>
#include <cstdint>
#include <iostream>
#include <thread>

namespace {

// 对应 base::AtomicFlag:std::atomic<uint_fast8_t> 的语义收窄封装
// 一次性(无 public clear)+ 单序列写(DCHECK,这里省略)+ release/acquire
class AtomicFlag {
public:
void Set() noexcept {
flag_.store(1, std::memory_order_release); // 发布"Set 之前的写"
}
bool IsSet() const noexcept {
return flag_.load(std::memory_order_acquire) != 0; // acquire:建立 happens-before
}

private:
std::atomic<uint_fast8_t> flag_{0};
};

} // namespace

int main() {
std::cout << "=== AtomicFlag 基本行为 ===\n";
AtomicFlag f;
std::cout << " 初始 IsSet=" << f.IsSet() << "\n";
f.Set();
std::cout << " Set 后 IsSet=" << f.IsSet() << "\n";

std::cout << "\n=== release/acquire 建立跨线程 happens-before ===\n";
// 线程 A:写 data,然后 Set(release)
// 线程 B:IsSet(acquire)看到 true ⇒ 必然看到 data==42
int data = 0;
AtomicFlag ready;

std::thread producer([&] {
data = 42; // (1) 普通写
ready.Set(); // (2) release-store:把 (1) 发布出去
});
std::thread consumer([&] {
while (!ready.IsSet()) {
} // (3) acquire-load:等 release
std::cout << " consumer 看到 data=" << data << " (期望 42)\n"; // (4) 保证看到 (1)
});
producer.join();
consumer.join();

std::cout << "\n=== 对比 relaxed:不建立同步,可能读到旧值 ===\n";
std::cout << " (relaxed 只保证原子,不传递 data 的可见性 —— 本质上不能用来做 liveness flag)\n";
std::cout
<< " AtomicFlag 选 release/acquire 正是为了让 WeakPtr 的 IsValid 看到对象的全部状态\n";
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// SequenceChecker:lazy 序列绑定 + debug 抓跨线程违规(release 下 0 字节 no-op)
// 来源:WeakPtr 前置知识(三):序列、SEQUENCE_CHECKER 与 DCHECK/CHECK (pre-03)
// 编译:g++ -std=c++17 -Wall -Wextra 14_sequence_checker.cpp -o 14_sequence_checker -pthread
// debug:g++ -std=c++17 ... (默认,带 assert);release:g++ -std=c++17 -DNDEBUG ...

#include <cassert>
#include <iostream>
#include <thread>

namespace {

// 教学版:用 std::thread::id 模拟"序列"(Chromium 用 SequenceToken,更细)
// release(NDEBUG)下全 no-op,0 字节成员 —— 对应 SEQUENCE_CHECKER 三宏
#if defined(NDEBUG)
class SequenceChecker {
public:
void detach_from_sequence() noexcept {}
bool called_on_valid_sequence() const noexcept { return true; }
};
#else
# include <thread>
class SequenceChecker {
public:
void detach_from_sequence() noexcept { bound_ = std::thread::id{}; } // 构造时:未绑定
bool called_on_valid_sequence() const noexcept {
if (bound_ == std::thread::id{}) {
bound_ = std::this_thread::get_id(); // lazy 绑定:首次触碰才定
return true;
}
return bound_ == std::this_thread::get_id();
}

private:
mutable std::thread::id bound_;
};
#endif

// 模拟 WeakPtr::Flag 的 lazy 绑定用法
class Flag {
public:
Flag() { seq_.detach_from_sequence(); } // 构造:未绑定
void Invalidate() {
assert(seq_.called_on_valid_sequence()); // 首次触碰 → 绑定到当前线程
invalidated_ = true;
}
bool IsValid() const {
assert(seq_.called_on_valid_sequence()); // 之后必须在同线程
return !invalidated_;
}

private:
SequenceChecker seq_;
bool invalidated_ = false;
};

} // namespace

int main() {
std::cout << "=== lazy 序列绑定(单线程,正常路径)==\n";
Flag flag; // 构造在主线程,detach(未绑定)
std::cout << " 主线程 IsValid=" << flag.IsValid() << "(首次触碰 → 绑定到主线程)\n";
flag.Invalidate();
std::cout << " Invalidate 后 IsValid=" << flag.IsValid() << "\n";

std::cout << "\n=== 跨线程违规(debug 下 assert 失败)==\n";
std::cout << " 下面的注释代码演示违规:在另一线程调 IsValid 会触发 assert\n";
// 取消下面注释在 debug 构建跑,会 abort:
// std::thread t([&flag] { (void)flag.IsValid(); }); // 不在绑定线程 → assert 失败
// t.join();

std::cout << "\n=== release 构建(DNDEBUG)下零开销 ===\n";
// 注意:本教学版用真实空类模拟 SequenceChecker,C++ 空类对象 sizeof = 1(最低 1 字节)。
// 真实 Chromium 的 SEQUENCE_CHECKER(name) 宏在 release 下展开为 static_assert(true, ""),
// 根本不生成成员 → 对宿主类 sizeof 贡献 0 字节(见文章 pre-03)。
// 这里打印的是教学版空类的 sizeof,不是 Chromium 的真实行为。
std::cout << " 教学版 sizeof(SequenceChecker) = " << sizeof(SequenceChecker)
<< "(空类,C++ 保证 ≥1 字节;debug 下为 thread::id 通常 8 字节)\n";
std::cout << " 真实 Chromium:宏展开为 static_assert,0 字节成员 —— 比教学版更极致\n";
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// concepts 与 requires:WeakPtr 的转换构造约束 + 成员函数 const 重载
// 来源:WeakPtr 前置知识(四):concepts 与 requires 在 WeakPtr 里的应用 (pre-04)
// 编译:g++ -std=c++20 -Wall -Wextra 15_concepts_requires.cpp -o 15_concepts_requires

#include <concepts>
#include <iostream>
#include <type_traits>
#include <typeinfo>

namespace {

struct Base {
virtual ~Base() = default;
virtual int kind() const { return 0; }
};
struct Derived : Base {
int kind() const override { return 1; }
};

// 简化版 WeakPtr,只保留转换构造 + const 重载这两个 concept 用法
template <typename T> class MiniWeakPtr {
public:
MiniWeakPtr() = default;

// 向上转型转换构造:requires(std::convertible_to<U*, T*>)
template <typename U>
requires(std::convertible_to<U*, T*>)
MiniWeakPtr(const MiniWeakPtr<U>&) noexcept {
std::cout << " [转换构造] WeakPtr<" << typeid(U).name() << "> -> WeakPtr<"
<< typeid(T).name() << ">\n";
}
};

// 简化版 WeakPtrFactory:GetWeakPtr 的 const/非 const 重载用 requires(!is_const_v<T>)
template <typename T> class MiniFactory {
public:
explicit MiniFactory(T* p) : ptr_(p) {}

// const factory → WeakPtr<const T>
void get() const { std::cout << " [const 重载] 返回 WeakPtr<const T>\n"; }
// 非 const factory → WeakPtr<T>,仅在 T 非 const 时存在
void get()
requires(!std::is_const_v<T>)
{
std::cout << " [非 const 重载] 返回 WeakPtr<T>(可变)\n";
}

private:
T* ptr_;
};

} // namespace

int main() {
std::cout << "=== 转换构造:向上转型合法 ===\n";
MiniWeakPtr<Derived> wd;
MiniWeakPtr<Base> wb = wd; // ✓ Derived* → Base* 满足 convertible_to
std::cout << " Derived -> Base: OK\n";
// MiniWeakPtr<Derived> wd2 = wb; // ✗ Base* -> Derived* 不满足,编译错(constraints not
// satisfied)

std::cout << "\n=== const 正确性:成员函数 requires ===\n";
Derived d;

std::cout << " MiniFactory<Derived>:\n";
MiniFactory<Derived> fac(&d);
const MiniFactory<Derived> cf(&d);
std::cout << " 非 const .get(): ";
fac.get();
std::cout << " const .get(): ";
cf.get();

std::cout << "\n MiniFactory<const Derived>(T 已是 const → 非 const 重载被 "
"requires(!is_const_v) 干掉):\n";
MiniFactory<const Derived> cfac(&d);
std::cout << " .get(): ";
cfac.get(); // 只剩 const 重载
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// WeakPtr 核心骨架演示:Flag/WeakReference/WeakPtr 三层 + get/invalidate 行为
// 来源:WeakPtr 实战(二):核心骨架与控制块 (02-2)
// 编译:g++ -std=c++20 -Wall -Wextra -I. 16_weak_ptr_skeleton.cpp -o 16_weak_ptr_skeleton -pthread

#include "weak_ptr.hpp"

#include <iostream>

struct Foo {
int x = 42;
int get() const { return x; }
};

int main() {
using namespace tamcpp::chrome;
Foo foo{7};

// 一个 factory 挂在 foo 上(教学:这里直接用 factory,真实场景见 17_weak_ptr_factory)
WeakPtrFactory<Foo> fac(&foo);

std::cout << "=== WeakPtr 基本行为 ===\n";
auto wp = fac.get_weak_ptr();
std::cout << " wp 判活=" << (wp ? "yes" : "no") << ", get()=" << wp.get()
<< ", wp->x=" << wp->x << "\n";

std::cout << "\n=== invalidate 后 ===\n";
fac.invalidate_weak_ptrs();
std::cout << " wp 判活=" << (wp ? "yes" : "no") << ", get()=" << wp.get() << "\n";
std::cout << " was_invalidated=" << wp.was_invalidated() << " (区分被作废 vs 主动 reset)\n";
// 注意:wp->x 此刻会 assert/debug abort —— 对应 Chromium 的 CHECK
std::cout << " (operator* / operator-> 在失效时 assert/CHECK,这里不再调用)\n";

std::cout << "\n=== sizeof WeakPtr ===\n";
std::cout << " sizeof(WeakPtr<Foo>) = " << sizeof(WeakPtr<Foo>)
<< " (WeakReference + T*,两个指针)\n";
std::cout << " WeakPtrFactory 铸的所有 WeakPtr 共享同一枚 Flag → invalidate 一次集体失效\n";
return 0;
}
Loading
Loading