测试_第26章_手写容器.cpp

← 测试总览 · 目录

编译运行:clang++ -std=c++26 -Wall -Wextra -pthread 测试_第26章_手写容器.cpp -o t && ./t(需先 cd 测试/

// 第26章测试:手写 STL 组件
#include <print>
#include <memory>
#include <cstring>
#include <algorithm>
#include <ranges>
#include <type_traits>

int failures = 0;
#define CHECK(expr)                                                         \
    do {                                                                    \
        if (!(expr)) {                                                      \
            ++failures;                                                     \
            std::println("FAIL 第{}行: {}", __LINE__, #expr);              \
        }                                                                   \
    } while (0)

// 分配计数:验证构造/析构配对
struct Tracked {
    static inline int alive = 0;
    int v = 0;
    explicit Tracked(int x = 0) : v(x) { ++alive; }
    Tracked(const Tracked& o) : v(o.v) { ++alive; }
    Tracked(Tracked&& o) noexcept : v(o.v) { ++alive; }
    Tracked& operator=(const Tracked&) = default;
    ~Tracked() { --alive; }
};

// 26.2 MyVector
template <typename T>
class MyVector {
public:
    MyVector() = default;
    MyVector(const MyVector& o) { copy_from(o); }
    MyVector(MyVector&& o) noexcept
        : begin_(o.begin_), end_(o.end_), capacity_(o.capacity_) {
        o.begin_ = o.end_ = o.capacity_ = nullptr;
    }
    MyVector& operator=(const MyVector& o) {
        if (this != &o) { release(); copy_from(o); }
        return *this;
    }
    MyVector& operator=(MyVector&& o) noexcept {
        if (this != &o) {
            release();
            begin_ = o.begin_; end_ = o.end_; capacity_ = o.capacity_;
            o.begin_ = o.end_ = o.capacity_ = nullptr;
        }
        return *this;
    }
    ~MyVector() { release(); }

    void push_back(const T& v) {
        if (end_ == capacity_) grow();
        new (end_) T(v);
        ++end_;
    }
    void push_back(T&& v) {
        if (end_ == capacity_) grow();
        new (end_) T(std::move(v));
        ++end_;
    }
    template <typename... Args>
    void emplace_back(Args&&... args) {
        if (end_ == capacity_) grow();
        new (end_) T(std::forward<Args>(args)...);
        ++end_;
    }
    T& operator[](std::size_t i) { return begin_[i]; }
    const T& operator[](std::size_t i) const { return begin_[i]; }
    std::size_t size() const { return end_ - begin_; }
    std::size_t capacity() const { return capacity_ - begin_; }
    T* begin() { return begin_; }
    T* end() { return end_; }
    const T* begin() const { return begin_; }
    const T* end() const { return end_; }
private:
    void grow() {
        std::size_t old_size = size();                      // 先记旧 size!
        std::size_t new_cap = capacity() == 0 ? 4 : capacity() * 2;
        T* new_begin = reinterpret_cast<T*>(new char[new_cap * sizeof(T)]);
        for (std::size_t i = 0; i < old_size; ++i)
            new (new_begin + i) T(std::move(begin_[i]));    // 移动元素
        release_no_free(new_begin, new_begin + old_size);   // 析构旧元素
        delete[] reinterpret_cast<char*>(begin_);
        begin_ = new_begin;
        end_ = new_begin + old_size;
        capacity_ = new_begin + new_cap;
    }
    void copy_from(const MyVector& o) {
        if (o.size() == 0) return;
        begin_ = reinterpret_cast<T*>(new char[o.size() * sizeof(T)]);
        for (std::size_t i = 0; i < o.size(); ++i)
            new (begin_ + i) T(o.begin_[i]);
        end_ = begin_ + o.size();
        capacity_ = end_;
    }
    void release_no_free(T*, T*) {
        std::destroy(begin_, end_);
    }
    void release() {
        std::destroy(begin_, end_);
        delete[] reinterpret_cast<char*>(begin_);
        begin_ = end_ = capacity_ = nullptr;
    }
    T* begin_ = nullptr;
    T* end_ = nullptr;
    T* capacity_ = nullptr;
};

// 26.3 MyUniquePtr
template <typename T>
class MyUniquePtr {
public:
    MyUniquePtr() = default;
    explicit MyUniquePtr(T* p) : ptr_(p) {}
    ~MyUniquePtr() { delete ptr_; }
    MyUniquePtr(const MyUniquePtr&) = delete;
    MyUniquePtr& operator=(const MyUniquePtr&) = delete;
    MyUniquePtr(MyUniquePtr&& o) noexcept : ptr_(o.ptr_) { o.ptr_ = nullptr; }
    MyUniquePtr& operator=(MyUniquePtr&& o) noexcept {
        if (this != &o) { delete ptr_; ptr_ = o.ptr_; o.ptr_ = nullptr; }
        return *this;
    }
    T& operator*() const { return *ptr_; }
    T* operator->() const { return ptr_; }
    T* get() const { return ptr_; }
    explicit operator bool() const { return ptr_ != nullptr; }
    T* release() { T* p = ptr_; ptr_ = nullptr; return p; }
    void reset(T* p = nullptr) { delete ptr_; ptr_ = p; }
private:
    T* ptr_ = nullptr;
};

// 26.4 MyString(简化版,无 SSO)
class MyString {
public:
    MyString() = default;
    MyString(const char* s) { assign(s); }
    MyString(const MyString& o) { assign(o.c_str()); }
    MyString(MyString&& o) noexcept : data_(o.data_), size_(o.size_) {
        o.data_ = nullptr; o.size_ = 0;
    }
    MyString& operator=(const MyString& o) {
        if (this != &o) assign(o.c_str());
        return *this;
    }
    MyString& operator=(MyString&& o) noexcept {
        if (this != &o) {
            delete[] data_;
            data_ = o.data_; size_ = o.size_;
            o.data_ = nullptr; o.size_ = 0;
        }
        return *this;
    }
    ~MyString() { delete[] data_; }
    void assign(const char* s) {
        delete[] data_;
        size_ = std::strlen(s);
        data_ = new char[size_ + 1];
        std::memcpy(data_, s, size_ + 1);
    }
    const char* c_str() const { return data_ ? data_ : ""; }
    std::size_t size() const { return size_; }
    char operator[](std::size_t i) const { return data_[i]; }
private:
    char* data_ = nullptr;
    std::size_t size_ = 0;
};

int main() {
    // ===== MyVector 基本功能 =====
    {
        MyVector<Tracked> v;
        CHECK(v.size() == 0);
        v.push_back(Tracked(1));
        v.push_back(Tracked(2));
        v.push_back(Tracked(3));          // 触发扩容(cap 4)
        v.push_back(Tracked(4));
        v.push_back(Tracked(5));          // 触发扩容(cap 8)
        CHECK(v.size() == 5);
        CHECK(v.capacity() >= 5);
        CHECK(v[0].v == 1 && v[4].v == 5);
        CHECK(Tracked::alive == 5);       // 容器里恰好 5 个存活

        // emplace_back
        v.emplace_back(6);
        CHECK(v.size() == 6 && v[5].v == 6);
    }                                     // 离开作用域全部析构
    CHECK(Tracked::alive == 0);           // 零泄漏!

    // 拷贝与移动
    {
        MyVector<int> a;
        for (int i = 0; i < 10; ++i) a.push_back(i);
        MyVector<int> b = a;              // 拷贝
        CHECK(b.size() == 10 && b[9] == 9);
        b[0] = 99;
        CHECK(a[0] == 0);                 // 深拷贝独立
        MyVector<int> c = std::move(a);   // 移动
        CHECK(c.size() == 10 && c[9] == 9);
    }

    // 迭代器 + 范围 for + 算法
    {
        MyVector<int> v;
        for (int i = 0; i < 10; ++i) v.push_back(i * i);
        int sum = 0;
        for (int x : v) sum += x;
        CHECK(sum == 285);                // 0+1+4+...+81
        std::ranges::sort(v);             // 迭代器兼容 STL 算法
        CHECK(std::ranges::is_sorted(v));
        auto it = std::ranges::find(v, 25);
        CHECK(it != v.end() && *it == 25);
    }

    // ===== MyUniquePtr =====
    {
        MyUniquePtr<Tracked> p(new Tracked(7));
        CHECK(p.get() != nullptr);
        CHECK((*p).v == 7);
        CHECK(p->v == 7);
        CHECK(static_cast<bool>(p));
        Tracked* raw = p.release();       // 转移出去
        CHECK(p.get() == nullptr);
        delete raw;                       // 手动释放
        CHECK(Tracked::alive == 0);
        MyUniquePtr<Tracked> q(new Tracked(1));
        MyUniquePtr<Tracked> r = std::move(q);
        CHECK(q.get() == nullptr && r->v == 1);
        r.reset();                        // 立即释放
        CHECK(Tracked::alive == 0);
    }
    // 编译期验证:不可拷贝
    static_assert(!std::is_copy_constructible_v<MyUniquePtr<int>>);
    static_assert(std::is_move_constructible_v<MyUniquePtr<int>>);

    // ===== MyString =====
    {
        MyString s("hello");
        CHECK(s.size() == 5);
        CHECK(s[0] == 'h' && s[4] == 'o');
        CHECK(std::strcmp(s.c_str(), "hello") == 0);
        MyString copy = s;                // 拷贝
        CHECK(std::strcmp(copy.c_str(), "hello") == 0);
        MyString moved = std::move(s);    // 移动
        CHECK(std::strcmp(moved.c_str(), "hello") == 0);
        copy.assign("world");
        CHECK(std::strcmp(copy.c_str(), "world") == 0);
    }

    if (failures == 0) std::println("全部通过");
    return failures;
}