手搓之C++工程系列

2025-12-24 · 传统算法
智能指针、LRU与多线程等

还是栽在一些面试八股题上了,给我算法题还好,写个小模板就能唬住一些没打过竞赛的面试官。但是让我写工程类题目(手搓智能指针、LRU、多线程消费)我就有点头疼,一个是一个C++工程里最多用一次这种玩意,另一个是我写C++工程也少,在这里整理一下常见的C++八股工程。


LRU缓存

以下是一个存储int为键、int为值的LRU缓存实现。

#include <list>
#include <unordered_map>

using namespace std;

class LRUCache {
public:
    LRUCache(int capacity) : cap_(capacity) {}

    int get(int key) {
        auto it = mp_.find(key);
        if (it == mp_.end()) return -1;

        // splice 意为“绞接”
        lst_.splice(lst_.begin(), lst_, it->second);
        return it->second->second;
    }

    void put(int key, int value) {
        auto it = mp_.find(key);
        if (it != mp_.end()) {
            it->second->second = value;
            lst_.splice(lst_.begin(), lst_, it->second);
            return;
        }

        if ((int)lst_.size() == cap_) {
            int old_key = lst_.back().first;
            mp_.erase(old_key);
            lst_.pop_back();
        }

        lst_.push_front({key, value});
        mp_[key] = lst_.begin();
    }

private:
    int cap_;
    list<pair<int,int>> lst_; 
    unordered_map<int, list<pair<int,int>>::iterator> mp_;
};

感觉说白了出这个题就是面试官想挂人,没想到我考场上搓出来了,哈哈。


智能指针

unique_ptr

template <typename T>
class UniquePtr {
public:
    // 构造:接管裸指针
    explicit UniquePtr(T* ptr = nullptr) : ptr_(ptr) {}

    ~UniquePtr() {delete ptr_;}

    // 禁止拷贝:防止多个指针同时拥有同一资源
    UniquePtr(const UniquePtr&) = delete;
    UniquePtr& operator=(const UniquePtr&) = delete;

    // 允许移动:转移所有权,noexcept保证扩容等场景不会fallback到拷贝
    UniquePtr(UniquePtr&& other) noexcept : ptr_(other.ptr_) {
        other.ptr_ = nullptr;  
    }

    UniquePtr& operator=(UniquePtr&& other) noexcept {
        if (this != &other) {
            delete ptr_;        // ★ 先释放自己原来的资源
            ptr_ = other.ptr_;
            other.ptr_ = nullptr;
        }
        return *this;
    }

    // 解引用
    T& operator*() const { return *ptr_; }
    T* operator->() const { return ptr_; }
    T* get() const { return ptr_; }

    // 释放所有权,返回裸指针(调用者负责 delete)
    T* release() {
        T* tmp = ptr_;
        ptr_ = nullptr;
        return tmp;
    }

    // 重置指针
    void reset(T* ptr = nullptr) {
        if (ptr_ != ptr) {
            delete ptr_;
            ptr_ = ptr;
        }
    }



private:
    T* ptr_;
};

shared_ptr

template <typename T>
class SharedPtr {
public:
    // 构造:创建控制块(这里只用一个 int 做引用计数)
    explicit SharedPtr(T* ptr = nullptr)
        : ptr_(ptr), count_(ptr ? new int(1) : nullptr) {}

    // 拷贝构造:共享资源,引用计数 +1
    SharedPtr(const SharedPtr& other)
        : ptr_(other.ptr_), count_(other.count_) {
        if (count_) ++(*count_);  
    }

    // 拷贝赋值
    SharedPtr& operator=(const SharedPtr& other) {
        if (this != &other) {
            release();          // ★ 先释放当前持有的资源
            ptr_ = other.ptr_;
            count_ = other.count_;
            if (count_) ++(*count_);
        }
        return *this;
    }

    // 析构:减少引用计数,为 0 时真正释放资源
    ~SharedPtr() {release();}

    // 解引用
    T& operator*() const { return *ptr_; }
    T* operator->() const { return ptr_; }
    T* get() const { return ptr_; }

    int use_count() const {return count_ ? *count_ : 0;}

    // 重置指针
    void reset(T* ptr = nullptr) {
        release();
        if (ptr) {
            ptr_ = ptr;
            count_ = new int(1);
        }
    }

private:
    void release() {
        if (count_ && --(*count_) == 0) {
            delete ptr_;    // ★ 最后一个 SharedPtr 负责释放资源
            delete count_;
        }
        ptr_ = nullptr;
        count_ = nullptr;
    }
    T* ptr_;
    int* count_;  
};

多线程

多消费者

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>

using namespace std;

int resource = 10;          
mutex mtx;
condition_variable cv;

void consumer(int id) {
    while (true) {
        unique_lock<mutex> lk(mtx);
        cv.wait(lk, [] { return resource > 0; });

        if (resource == 0) break;   // 安全退出
        --resource;                 // 消费资源
        cout << "consumer " << id << " consumed, left=" << resource << endl;
    }
}

int main() {
    vector<thread> threads;
    for (int i = 0; i < 3; ++i)threads.emplace_back(consumer, i);
    cv.notify_all();                 // 启动消费者
    for (auto& t : threads) t.join();
}

循环打印奇偶数

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

using namespace std;

int cur = 1;
const int N = 10;
mutex mtx;
condition_variable cv;

void print_odd() {
    while (true) {
        unique_lock<mutex> lk(mtx);
        cv.wait(lk, [] { return cur > N || cur % 2 == 1; });
        if (cur > N) break;
        cout << cur++ << " ";
        cv.notify_all();
    }
}

void print_even() {
    while (true) {
        unique_lock<mutex> lk(mtx);
        cv.wait(lk, [] { return cur > N || cur % 2 == 0; });
        if (cur > N) break;
        cout << cur++ << " ";
        cv.notify_all();
    }
}

int main() {
    thread t1(print_odd);
    thread t2(print_even);

    t1.join();
    t2.join();
}

设计模式

单例模式

class Singleton {
public:
    // 获取唯一实例:C++11 起函数内 static 初始化线程安全
    static Singleton& instance() {
        static Singleton inst;   // 懒加载:第一次调用才构造
        return inst;
    }

    void foo() {}

    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    Singleton& operator=(Singleton&&) = delete;

private:
    Singleton() = default;   // 构造私有化
    ~Singleton() = default;  // 析构私有/默认(由静态对象生命周期管理)
};