完整教程:C++面试题及详细答案100道( 71-80 )

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

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

在这里插入图片描述

一、本文面试题目录

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

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

示例代码

#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. 如何实现一个简单的线程池?

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

示例代码

#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. 如何实现一个简单的生产者-消费者模型?

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

示例代码

#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. 如何实现一个简单的观察者模式(基于事件总线)?

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

示例代码

#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. 如何实现一个简单的状态机?

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

示例代码

#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. 如何实现一个简单的内存管理器?

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

示例代码

#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)在编译期执行计算,将运行时开销转移到编译期。

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

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. 如何实现一个简单的协程?

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

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

#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. 如何实现一个简单的事件驱动系统?

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

示例代码

#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(资源获取即初始化)通过对象生命周期管理资源,确保资源正确释放。

示例代码

#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道
1C++面试题及详细答案100道(01-10)
2C++面试题及详细答案100道(11-20)
3C++面试题及详细答案100道(21-30)
4C++面试题及详细答案100道(31-40)
5C++面试题及详细答案100道(41-50)
6C++面试题及详细答案100道(51-60)
7C++面试题及详细答案100道(61-70)
8C++面试题及详细答案100道(71-80)
9C++面试题及详细答案100道(81-90)
10C++面试题及详细答案100道(91-100)
posted @ 2025-12-15 17:23  clnchanpin  阅读(42)  评论(0)    收藏  举报