C++面试题及详细答案100道( 71-80 )

前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux... 。

前后端面试题-专栏总目录

文章目录

  • 一、本文面试题目录
      • [71. 如何实现一个简单的内存池?](#71. 如何实现一个简单的内存池?)
      • [72. 如何实现一个简单的线程池?](#72. 如何实现一个简单的线程池?)
      • [73. 如何实现一个简单的生产者-消费者模型?](#73. 如何实现一个简单的生产者-消费者模型?)
      • [74. 如何实现一个简单的观察者模式(基于事件总线)?](#74. 如何实现一个简单的观察者模式(基于事件总线)?)
      • [75. 如何实现一个简单的状态机?](#75. 如何实现一个简单的状态机?)
      • [76. 如何实现一个简单的内存管理器?](#76. 如何实现一个简单的内存管理器?)
      • [77. 如何实现一个简单的模板元编程示例?](#77. 如何实现一个简单的模板元编程示例?)
      • [78. 如何实现一个简单的协程?](#78. 如何实现一个简单的协程?)
      • [79. 如何实现一个简单的事件驱动系统?](#79. 如何实现一个简单的事件驱动系统?)
      • [80. 如何实现一个简单的RAII资源管理器?](#80. 如何实现一个简单的RAII资源管理器?)
  • 二、100道面试题目录列表

一、本文面试题目录

71. 如何实现一个简单的内存池?

答案

内存池预分配大块内存,减少频繁系统调用带来的开销,提高内存分配效率。

示例代码

cpp 复制代码
#include <vector>
#include <stack>
#include <cstddef>

class MemoryPool {
private:
    std::vector<char*> blocks;       // 存储分配的大块内存
    std::stack<char*> freeChunks;    // 存储空闲内存块
    size_t chunkSize;                // 每个内存块的大小
    size_t blockSize;                // 每次分配的大块内存大小

public:
    MemoryPool(size_t chunkSize, size_t blockSize = 1024)
        : chunkSize(chunkSize), blockSize(blockSize) {
        allocateBlock();
    }

    ~MemoryPool() {
        for (char* block : blocks) {
            delete[] block;
        }
    }

    void* allocate() {
        if (freeChunks.empty()) {
            allocateBlock();
        }

        char* chunk = freeChunks.top();
        freeChunks.pop();
        return chunk;
    }

    void deallocate(void* ptr) {
        if (ptr) {
            freeChunks.push(static_cast<char*>(ptr));
        }
    }

private:
    void allocateBlock() {
        char* block = new char[chunkSize * blockSize];
        blocks.push_back(block);

        // 将大块内存分割成多个内存块并加入空闲列表
        for (size_t i = 0; i < blockSize; ++i) {
            freeChunks.push(block + i * chunkSize);
        }
    }
};

原理

  • 预分配大块内存,将其分割为固定大小的内存块。
  • 使用栈管理空闲内存块,分配时直接从栈顶获取,释放时放回栈顶。
  • 减少系统调用次数,降低内存碎片。

72. 如何实现一个简单的线程池?

答案

线程池维护固定数量的工作线程,避免频繁创建和销毁线程的开销,提高并发性能。

示例代码

cpp 复制代码
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <atomic>

class ThreadPool {
private:
    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;
    std::mutex queueMutex;
    std::condition_variable condition;
    std::atomic<bool> stop;

public:
    explicit ThreadPool(size_t numThreads) : stop(false) {
        for (size_t i = 0; i < numThreads; ++i) {
            workers.emplace_back([this] {
                while (true) {
                    std::function<void()> task;
                    {
                        std::unique_lock<std::mutex> lock(this->queueMutex);
                        this->condition.wait(lock, [this] {
                            return this->stop || !this->tasks.empty();
                        });
                        if (this->stop && this->tasks.empty())
                            return;
                        task = std::move(this->tasks.front());
                        this->tasks.pop();
                    }
                    task();
                }
            });
        }
    }

    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(queueMutex);
            stop = true;
        }
        condition.notify_all();
        for (std::thread& worker : workers) {
            worker.join();
        }
    }

    template<class F>
    void enqueue(F&& f) {
        {
            std::unique_lock<std::mutex> lock(queueMutex);
            if (stop)
                throw std::runtime_error("enqueue on stopped ThreadPool");
            tasks.emplace(std::forward<F>(f));
        }
        condition.notify_one();
    }
};

原理

  • 预先创建固定数量的工作线程,线程不断从任务队列获取任务执行。
  • 任务队列使用互斥锁和条件变量实现线程安全。
  • 线程池析构时通知所有线程停止工作并等待它们完成。

73. 如何实现一个简单的生产者-消费者模型?

答案

生产者-消费者模型通过共享缓冲区解耦数据生产和消费,使用同步机制确保线程安全。

示例代码

cpp 复制代码
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>

template<typename T>
class ProducerConsumerQueue {
private:
    std::queue<T> queue;
    std::mutex mutex;
    std::condition_variable notEmpty;
    std::condition_variable notFull;
    size_t maxSize;

public:
    explicit ProducerConsumerQueue(size_t size) : maxSize(size) {}

    void produce(const T& item) {
        std::unique_lock<std::mutex> lock(mutex);
        notFull.wait(lock, [this] { return queue.size() < maxSize; });
        queue.push(item);
        notEmpty.notify_one();
    }

    T consume() {
        std::unique_lock<std::mutex> lock(mutex);
        notEmpty.wait(lock, [this] { return !queue.empty(); });
        T item = queue.front();
        queue.pop();
        notFull.notify_one();
        return item;
    }
};

// 使用示例
void producer(ProducerConsumerQueue<int>& queue) {
    for (int i = 0; i < 10; ++i) {
        queue.produce(i);
        std::cout << "Produced: " << i << std::endl;
    }
}

void consumer(ProducerConsumerQueue<int>& queue) {
    for (int i = 0; i < 10; ++i) {
        int item = queue.consume();
        std::cout << "Consumed: " << item << std::endl;
    }
}

原理

  • 使用有界队列作为缓冲区,生产者向队列添加数据,消费者从队列取出数据。
  • 两个条件变量分别用于等待队列非空(消费者)和队列非满(生产者)。
  • 互斥锁保护队列的读写操作,确保线程安全。

74. 如何实现一个简单的观察者模式(基于事件总线)?

答案

事件总线模式是观察者模式的扩展,通过中央事件管理器解耦发布者和订阅者。

示例代码

cpp 复制代码
#include <unordered_map>
#include <vector>
#include <functional>
#include <mutex>

class EventBus {
private:
    using EventHandler = std::function<void(const void*)>;
    std::unordered_map<std::string, std::vector<EventHandler>> subscribers;
    std::mutex mutex;

public:
    void subscribe(const std::string& eventType, EventHandler handler) {
        std::lock_guard<std::mutex> lock(mutex);
        subscribers[eventType].push_back(handler);
    }

    void publish(const std::string& eventType, const void* data = nullptr) {
        std::lock_guard<std::mutex> lock(mutex);
        auto it = subscribers.find(eventType);
        if (it != subscribers.end()) {
            for (const auto& handler : it->second) {
                handler(data);
            }
        }
    }
};

// 使用示例
struct UserLoggedInEvent {
    std::string username;
};

void onUserLoggedIn(const void* data) {
    const auto* event = static_cast<const UserLoggedInEvent*>(data);
    std::cout << "User " << event->username << " logged in." << std::endl;
}

// 注册事件
EventBus bus;
bus.subscribe("UserLoggedIn", onUserLoggedIn);

// 发布事件
UserLoggedInEvent event{"john_doe"};
bus.publish("UserLoggedIn", &event);

原理

  • 事件总线维护事件类型到处理函数的映射表。
  • 订阅者向总线注册对特定事件的处理函数。
  • 发布者通过总线发布事件,总线调用所有注册的处理函数。
  • 使用互斥锁确保线程安全。

75. 如何实现一个简单的状态机?

答案

状态机根据当前状态和输入执行状态转换,实现复杂的逻辑控制。

示例代码

cpp 复制代码
#include <unordered_map>
#include <functional>
#include <string>
#include <iostream>

class StateMachine {
public:
    using State = std::string;
    using Event = std::string;
    using Action = std::function<void()>;

    void addTransition(const State& from, const Event& event, const State& to, Action action = nullptr) {
        transitions[from][event] = {to, action};
    }

    void processEvent(const Event& event) {
        auto stateIt = transitions.find(currentState);
        if (stateIt != transitions.end()) {
            auto eventIt = stateIt->second.find(event);
            if (eventIt != stateIt->second.end()) {
                const Transition& transition = eventIt->second;
                if (transition.action) {
                    transition.action();
                }
                currentState = transition.to;
                std::cout << "State changed to: " << currentState << std::endl;
                return;
            }
        }
        std::cout << "Invalid event: " << event << " in state: " << currentState << std::endl;
    }

    void setInitialState(const State& state) {
        currentState = state;
    }

private:
    struct Transition {
        State to;
        Action action;
    };

    State currentState;
    std::unordered_map<State, std::unordered_map<Event, Transition>> transitions;
};

原理

  • 使用嵌套哈希表存储状态转换规则(当前状态→事件→目标状态+动作)。
  • processEvent()根据当前状态和事件查找转换规则,执行动作并更新状态。
  • 状态机可用于游戏AI、工作流引擎等场景。

76. 如何实现一个简单的内存管理器?

答案

内存管理器管理动态内存分配,优化内存使用并减少碎片。

示例代码

cpp 复制代码
#include <cstddef>
#include <cstdlib>
#include <vector>
#include <algorithm>

class MemoryManager {
private:
    struct Block {
        size_t size;
        bool free;
        Block* next;
    };

    Block* head;
    size_t totalMemory;

public:
    explicit MemoryManager(size_t size) : totalMemory(size) {
        head = static_cast<Block*>(std::malloc(sizeof(Block) + size));
        head->size = size;
        head->free = true;
        head->next = nullptr;
    }

    ~MemoryManager() {
        std::free(head);
    }

    void* allocate(size_t size) {
        Block* current = head;
        while (current) {
            if (current->free && current->size >= size) {
                // 分割块
                if (current->size > size + sizeof(Block)) {
                    Block* newBlock = reinterpret_cast<Block*>(reinterpret_cast<char*>(current) + sizeof(Block) + size);
                    newBlock->size = current->size - size - sizeof(Block);
                    newBlock->free = true;
                    newBlock->next = current->next;
                    current->next = newBlock;
                    current->size = size;
                }
                current->free = false;
                return reinterpret_cast<char*>(current) + sizeof(Block);
            }
            current = current->next;
        }
        return nullptr; // 内存不足
    }

    void deallocate(void* ptr) {
        if (!ptr) return;
        Block* block = reinterpret_cast<Block*>(reinterpret_cast<char*>(ptr) - sizeof(Block));
        block->free = true;
        mergeBlocks();
    }

private:
    void mergeBlocks() {
        Block* current = head;
        while (current && current->next) {
            if (current->free && current->next->free) {
                current->size += current->next->size + sizeof(Block);
                current->next = current->next->next;
            } else {
                current = current->next;
            }
        }
    }
};

原理

  • 使用空闲链表管理内存块,每个块包含大小、状态和指向下一块的指针。
  • 分配时查找足够大的空闲块,可选择分割。
  • 释放时标记块为空闲并合并相邻空闲块,减少碎片。

77. 如何实现一个简单的模板元编程示例?

答案

模板元编程(TMP)在编译期执行计算,将运行时开销转移到编译期。

示例代码(编译期斐波那契数列):

cpp 复制代码
template<int N>
struct Fibonacci {
    static constexpr int value = Fibonacci<N-1>::value + Fibonacci<N-2>::value;
};

// 特化终止条件
template<>
struct Fibonacci<0> {
    static constexpr int value = 0;
};

template<>
struct Fibonacci<1> {
    static constexpr int value = 1;
};

// 使用示例
int main() {
    constexpr int result = Fibonacci<5>::value; // 编译期计算斐波那契数列第5项(值为5)
    return 0;
}

原理

  • 模板递归实例化实现编译期计算。
  • 特化终止递归,避免无限展开。
  • 计算结果存储在静态常量中,运行时直接使用,无计算开销。

78. 如何实现一个简单的协程?

答案

协程允许函数在执行过程中暂停和恢复,保存上下文状态。

示例代码(简化版协程框架):

cpp 复制代码
#include <iostream>
#include <functional>
#include <vector>

class Coroutine {
public:
    using Task = std::function<void()>;

    enum class State {
        READY,
        RUNNING,
        SUSPENDED,
        FINISHED
    };

    explicit Coroutine(Task task) : task(task), state(State::READY) {}

    void resume() {
        if (state == State::READY || state == State::SUSPENDED) {
            state = State::RUNNING;
            if (!callStack.empty()) {
                // 恢复执行
                callStack.back()();
            } else {
                // 首次执行
                task();
            }
            if (state == State::RUNNING) {
                state = State::FINISHED;
            }
        }
    }

    void yield() {
        if (state == State::RUNNING) {
            state = State::SUSPENDED;
            // 使用longjmp/setjmp或context切换技术(此处简化)
            // 实际实现需要保存寄存器、栈等上下文
        }
    }

    State getState() const {
        return state;
    }

private:
    Task task;
    State state;
    std::vector<Task> callStack; // 简化的调用栈
};

原理

  • 协程通过保存和恢复执行上下文实现暂停和继续。
  • yield()保存当前状态并暂停执行,resume()恢复状态继续执行。
  • 实际实现需使用平台相关的上下文切换技术(如ucontext.h或汇编)。

79. 如何实现一个简单的事件驱动系统?

答案

事件驱动系统通过事件解耦组件,提高系统灵活性和可维护性。

示例代码

cpp 复制代码
#include <unordered_map>
#include <vector>
#include <functional>
#include <mutex>

class EventSystem {
public:
    using EventHandler = std::function<void(const std::vector<int>&)>;

    void subscribe(const std::string& eventType, EventHandler handler) {
        std::lock_guard<std::mutex> lock(mutex);
        subscribers[eventType].push_back(handler);
    }

    void unsubscribe(const std::string& eventType, EventHandler handler) {
        std::lock_guard<std::mutex> lock(mutex);
        auto it = subscribers.find(eventType);
        if (it != subscribers.end()) {
            auto& handlers = it->second;
            handlers.erase(std::remove(handlers.begin(), handlers.end(), handler), handlers.end());
        }
    }

    void publish(const std::string& eventType, const std::vector<int>& args = {}) {
        std::lock_guard<std::mutex> lock(mutex);
        auto it = subscribers.find(eventType);
        if (it != subscribers.end()) {
            for (const auto& handler : it->second) {
                handler(args);
            }
        }
    }

private:
    std::unordered_map<std::string, std::vector<EventHandler>> subscribers;
    std::mutex mutex;
};

原理

  • 事件系统维护事件类型到处理函数的映射。
  • 组件订阅感兴趣的事件,发布者通过系统发布事件。
  • 事件触发时,系统调用所有注册的处理函数。
  • 使用互斥锁确保线程安全。

80. 如何实现一个简单的RAII资源管理器?

答案

RAII(资源获取即初始化)通过对象生命周期管理资源,确保资源正确释放。

示例代码

cpp 复制代码
#include <iostream>
#include <functional>

template<typename T, typename D>
class ResourceManager {
private:
    T resource;
    D deleter;
    bool valid;

public:
    explicit ResourceManager(T res, D del) : resource(res), deleter(del), valid(true) {}

    ~ResourceManager() {
        if (valid) {
            deleter(resource);
        }
    }

    // 禁止拷贝
    ResourceManager(const ResourceManager&) = delete;
    ResourceManager& operator=(const ResourceManager&) = delete;

    // 允许移动
    ResourceManager(ResourceManager&& other) noexcept : 
        resource(other.resource), deleter(other.deleter), valid(other.valid) {
        other.valid = false;
    }

    ResourceManager& operator=(ResourceManager&& other) noexcept {
        if (this != &other) {
            if (valid) {
                deleter(resource);
            }
            resource = other.resource;
            deleter = other.deleter;
            valid = other.valid;
            other.valid = false;
        }
        return *this;
    }

    T get() const {
        return resource;
    }
};

// 使用示例
void* allocateMemory(size_t size) {
    return std::malloc(size);
}

void freeMemory(void* ptr) {
    std::free(ptr);
}

int main() {
    ResourceManager<void*, decltype(&freeMemory)> memory(allocateMemory(1024), freeMemory);
    // 内存会在memory对象析构时自动释放
    return 0;
}

原理

  • 构造时获取资源,析构时释放资源。
  • 禁用拷贝构造和赋值,防止资源重复释放。
  • 通过移动语义转移资源所有权。
  • 适用于文件句柄、网络连接、内存等资源管理。

二、100道面试题目录列表

文章序号 C++面试题100道
1 C++面试题及详细答案100道(01-10)
2 C++面试题及详细答案100道(11-20)
3 C++面试题及详细答案100道(21-30)
4 C++面试题及详细答案100道(31-40)
5 C++面试题及详细答案100道(41-50)
6 C++面试题及详细答案100道(51-60)
7 C++面试题及详细答案100道(61-70)
8 C++面试题及详细答案100道(71-80)
9 C++面试题及详细答案100道(81-90)
10 C++面试题及详细答案100道(91-100)
相关推荐
xlq223224 小时前
15.list(上)
数据结构·c++·list
Elias不吃糖5 小时前
总结我的小项目里现在用到的Redis
c++·redis·学习
AA陈超6 小时前
使用UnrealEngine引擎,实现鼠标点击移动
c++·笔记·学习·ue5·虚幻引擎
No0d1es6 小时前
电子学会青少年软件编程(C/C++)六级等级考试真题试卷(2025年9月)
c语言·c++·算法·青少年编程·图形化编程·六级
不会c嘎嘎7 小时前
每日一练 -- day1
c++·算法
yy_xzz7 小时前
VCPKG && Tesseract OCR
c++·图像处理·opencv
hansang_IR7 小时前
【记录】网络流最小割建模三题
c++·算法·网络流·最小割
玖笙&7 小时前
✨WPF编程进阶【7.3】集成动画(附源码)
c++·c#·wpf·visual studio
Dream it possible!7 小时前
LeetCode 面试经典 150_二叉树层次遍历_二叉树的层序遍历(83_102_C++_中等)
c++·leetcode·面试·二叉树
AA陈超8 小时前
Lyra源码分析:LyraCharacterMovementComponent
c++·笔记·学习·ue5·虚幻引擎·lyra