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

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

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

在这里插入图片描述

一、本文面试题目录

81. 如何实现一个简单的内存泄漏检测器?

答案
通过重载全局newdelete操作符,记录分配和释放的内存块。

示例代码

#include <unordered_map>
  #include <mutex>
    #include <iostream>
      struct AllocationRecord {
      size_t size;
      const char* file;
      int line;
      };
      static std::unordered_map<void*, AllocationRecord> g_allocations;
        static std::mutex g_mutex;
        void* operator new(size_t size, const char* file, int line) {
        void* ptr = std::malloc(size);
        if (ptr) {
        std::lock_guard<std::mutex> lock(g_mutex);
          g_allocations[ptr] = {size, file, line};
          }
          return ptr;
          }
          void operator delete(void* ptr) noexcept {
          if (ptr) {
          std::lock_guard<std::mutex> lock(g_mutex);
            g_allocations.erase(ptr);
            }
            std::free(ptr);
            }
            // 用于跟踪内存泄漏的宏
            #define new new(__FILE__, __LINE__)
            // 检查内存泄漏
            void checkMemoryLeaks() {
            std::lock_guard<std::mutex> lock(g_mutex);
              if (!g_allocations.empty()) {
              std::cerr << "Memory leaks detected:" << std::endl;
              for (const auto& pair : g_allocations) {
              const auto& record = pair.second;
              std::cerr << "  At " << record.file << ":" << record.line
              << ", size: " << record.size << " bytes" << std::endl;
              }
              } else {
              std::cout << "No memory leaks detected." << std::endl;
              }
              }
              // 使用示例
              int main() {
              int* leak = new int(42); // 未释放,会被检测为泄漏
              checkMemoryLeaks(); // 程序结束前检查
              return 0;
              }

原理

  • 重载new操作符时记录内存块地址、大小和分配位置。
  • 重载delete操作符时移除对应记录。
  • 程序结束前检查未释放的记录,输出泄漏信息。

82. 如何实现一个线程安全的观察者模式?

答案
在观察者模式基础上加入互斥锁,确保多线程环境下的线程安全。

示例代码

#include <vector>
  #include <mutex>
    #include <functional>
      #include <algorithm>
        class ThreadSafeObserver {
        public:
        virtual void update() = 0;
        virtual ~ThreadSafeObserver() = default;
        };
        class ThreadSafeSubject {
        private:
        std::vector<ThreadSafeObserver*> observers;
          mutable std::mutex mutex;
          public:
          void attach(ThreadSafeObserver* observer) {
          std::lock_guard<std::mutex> lock(mutex);
            observers.push_back(observer);
            }
            void detach(ThreadSafeObserver* observer) {
            std::lock_guard<std::mutex> lock(mutex);
              observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
              }
              void notify() {
              std::lock_guard<std::mutex> lock(mutex);
                for (auto observer : observers) {
                observer->update();
                }
                }
                };

原理

  • 使用std::mutex保护观察者列表的读写操作。
  • attachdetach操作加锁确保原子性。
  • notify操作加锁防止迭代过程中列表被修改。

83. 如何实现一个线程池的优雅关闭?

答案
通过状态控制和条件变量实现任务执行完毕后安全关闭线程池。

示例代码

#include <vector>
  #include <queue>
    #include <thread>
      #include <mutex>
        #include <condition_variable>
          #include <atomic>
            #include <functional>
              class ThreadPool {
              public:
              explicit ThreadPool(size_t numThreads) : stop(false), shuttingDown(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() {
                  shutdown();
                  }
                  void enqueue(std::function<void()> task) {
                    {
                    std::unique_lock<std::mutex> lock(queueMutex);
                      if (stop)
                      throw std::runtime_error("enqueue on stopped ThreadPool");
                      tasks.emplace(std::move(task));
                      }
                      condition.notify_one();
                      }
                      void shutdown() {
                      {
                      std::unique_lock<std::mutex> lock(queueMutex);
                        if (stop) return;
                        stop = true;
                        }
                        condition.notify_all();
                        for (std::thread& worker : workers) {
                        worker.join();
                        }
                        }
                        private:
                        std::vector<std::thread> workers;
                          std::queue<std::function<void()>> tasks;
                            std::mutex queueMutex;
                            std::condition_variable condition;
                            std::atomic<bool> stop;
                              std::atomic<bool> shuttingDown;
                                };

原理

  • 使用stop标志控制线程池状态。
  • shutdown方法将stop置为true,通知所有线程处理完现有任务后退出。
  • 线程通过条件变量等待任务或关闭信号,确保所有任务完成后才退出。

84. 如何实现一个简单的信号量?

答案
使用互斥锁和条件变量实现计数信号量。

示例代码

#include <mutex>
  #include <condition_variable>
    class Semaphore {
    public:
    explicit Semaphore(size_t count = 0) : count(count) {}
    void acquire() {
    std::unique_lock<std::mutex> lock(mutex);
      cv.wait(lock, [this] { return count > 0; });
      --count;
      }
      void release() {
      std::lock_guard<std::mutex> lock(mutex);
        ++count;
        cv.notify_one();
        }
        private:
        size_t count;
        std::mutex mutex;
        std::condition_variable cv;
        };

原理

  • count记录可用资源数量。
  • acquire等待资源(count > 0)并减少计数。
  • release增加计数并唤醒等待线程。

85. 如何实现一个简单的屏障(Barrier)?

答案
使用条件变量实现线程同步屏障。

示例代码

#include <mutex>
  #include <condition_variable>
    class Barrier {
    public:
    explicit Barrier(size_t numThreads) : count(numThreads), initialCount(numThreads) {}
    void wait() {
    std::unique_lock<std::mutex> lock(mutex);
      if (--count == 0) {
      generation++;
      count = initialCount;
      cv.notify_all();
      } else {
      auto currentGeneration = generation;
      cv.wait(lock, [this, currentGeneration] {
      return generation != currentGeneration;
      });
      }
      }
      private:
      size_t count;
      const size_t initialCount;
      size_t generation = 0;
      std::mutex mutex;
      std::condition_variable cv;
      };

原理

  • count记录等待的线程数,初始化为线程总数。
  • 每个线程调用wait时减少计数,最后一个线程唤醒所有等待线程。
  • generation用于区分不同轮次的屏障,避免虚假唤醒。

86. 如何实现一个简单的事件循环?

答案
使用队列和线程实现异步事件处理。

示例代码

#include <queue>
  #include <thread>
    #include <mutex>
      #include <condition_variable>
        #include <functional>
          #include <atomic>
            class EventLoop {
            public:
            EventLoop() : running(false) {}
            ~EventLoop() {
            stop();
            }
            void start() {
            if (running) return;
            running = true;
            thread = std::thread([this] { run(); });
            }
            void stop() {
            if (!running) return;
            {
            std::lock_guard<std::mutex> lock(mutex);
              running = false;
              cv.notify_all();
              }
              if (thread.joinable()) {
              thread.join();
              }
              }
              void post(std::function<void()> task) {
                {
                std::lock_guard<std::mutex> lock(mutex);
                  tasks.push(std::move(task));
                  }
                  cv.notify_one();
                  }
                  private:
                  void run() {
                  while (running) {
                  std::function<void()> task;
                    {
                    std::unique_lock<std::mutex> lock(mutex);
                      cv.wait(lock, [this] { return !running || !tasks.empty(); });
                      if (!running && tasks.empty()) return;
                      task = std::move(tasks.front());
                      tasks.pop();
                      }
                      task();
                      }
                      }
                      std::atomic<bool> running;
                        std::thread thread;
                        std::queue<std::function<void()>> tasks;
                          std::mutex mutex;
                          std::condition_variable cv;
                          };

原理

  • 事件循环在单独线程中运行,不断从队列中取出任务执行。
  • post方法将任务加入队列并唤醒事件线程。
  • stop方法停止循环并等待线程结束。

87. 如何实现一个简单的状态机(基于表驱动)?

答案
使用状态转换表实现状态机。

示例代码

#include <vector>
  #include <functional>
    #include <unordered_map>
      enum class State { IDLE, RUNNING, STOPPED };
      enum class Event { START, STOP, PAUSE };
      using Action = std::function<void()>;
        struct Transition {
        State nextState;
        Action action;
        };
        class StateMachine {
        private:
        State currentState;
        std::unordered_map<State, std::unordered_map<Event, Transition>> transitionTable;
          public:
          StateMachine() : currentState(State::IDLE) {
          // 初始化状态转换表
          transitionTable[State::IDLE][Event::START] = {State::RUNNING, [] {
          std::cout << "Starting..." << std::endl;
          }};
          transitionTable[State::RUNNING][Event::STOP] = {State::STOPPED, [] {
          std::cout << "Stopping..." << std::endl;
          }};
          // 添加其他转换...
          }
          void handleEvent(Event event) {
          auto stateIt = transitionTable.find(currentState);
          if (stateIt != transitionTable.end()) {
          auto eventIt = stateIt->second.find(event);
          if (eventIt != stateIt->second.end()) {
          const Transition& transition = eventIt->second;
          transition.action();
          currentState = transition.nextState;
          return;
          }
          }
          std::cout << "Invalid event: " << static_cast<int>(event)
            << " in state: " << static_cast<int>(currentState) << std::endl;
              }
              };

原理

  • 使用嵌套的unordered_map存储状态-事件-转换映射。
  • 每个转换包含下一个状态和执行动作。
  • handleEvent根据当前状态和事件查找转换并执行。

88. 如何实现一个简单的生产者-消费者队列(无锁)?

答案
使用原子操作和环形缓冲区实现无锁队列。

示例代码

#include <atomic>
  #include <vector>
    template<typename T, size_t Capacity>
      class LockFreeQueue {
      public:
      bool enqueue(const T& value) {
      size_t head = m_head.load(std::memory_order_relaxed);
      size_t tail = m_tail.load(std::memory_order_acquire);
      if ((tail + 1) % Capacity == head) {
      return false; // 队列满
      }
      m_data[tail] = value;
      m_tail.store((tail + 1) % Capacity, std::memory_order_release);
      return true;
      }
      bool dequeue(T& value) {
      size_t head = m_head.load(std::memory_order_relaxed);
      size_t tail = m_tail.load(std::memory_order_acquire);
      if (head == tail) {
      return false; // 队列空
      }
      value = m_data[head];
      m_head.store((head + 1) % Capacity, std::memory_order_release);
      return true;
      }
      private:
      std::vector<T> m_data{Capacity};
        alignas(64) std::atomic<size_t> m_head{0};
          alignas(64) std::atomic<size_t> m_tail{0};
            };

原理

  • 使用原子变量m_headm_tail分别表示队列头和尾。
  • 环形缓冲区实现循环利用空间。
  • 使用内存屏障(memory_order_acquire/release)保证操作顺序。

89 如何实现一个简单的智能指针(带弱引用)?

答案
实现引用计数和弱引用计数,支持弱指针检测对象是否存活。

示例代码

template<typename T>
  class WeakPtr;
  template<typename T>
    class SharedPtr {
    private:
    T* ptr;
    int* refCount;
    int* weakCount;
    public:
    explicit SharedPtr(T* p = nullptr) : ptr(p) {
    if (ptr) {
    refCount = new int(1);
    weakCount = new int(0);
    } else {
    refCount = nullptr;
    weakCount = nullptr;
    }
    }
    ~SharedPtr() {
    if (ptr && --(*refCount) == 0) {
    delete ptr;
    if (--(*weakCount) == 0) {
    delete refCount;
    delete weakCount;
    }
    }
    }
    // 拷贝构造、赋值运算符等...
    friend class WeakPtr<T>;
      };
      template<typename T>
        class WeakPtr {
        private:
        T* ptr;
        int* refCount;
        int* weakCount;
        public:
        WeakPtr() : ptr(nullptr), refCount(nullptr), weakCount(nullptr) {}
        WeakPtr(const SharedPtr<T>& other) : ptr(other.ptr), refCount(other.refCount), weakCount(other.weakCount) {
          if (weakCount) {
          ++(*weakCount);
          }
          }
          ~WeakPtr() {
          if (weakCount && --(*weakCount) == 0 && *refCount == 0) {
          delete refCount;
          delete weakCount;
          }
          }
          bool expired() const {
          return refCount == nullptr || *refCount == 0;
          }
          SharedPtr<T> lock() const {
            return expired() ? SharedPtr<T>() : SharedPtr<T>(ptr, refCount, weakCount);
              }
              };

原理

  • SharedPtr维护引用计数,管理对象生命周期。
  • WeakPtr维护弱引用计数,不影响对象生命周期。
  • expired()检查对象是否已被销毁,lock()获取共享指针(如果对象存活)。

90. 如何实现一个简单的缓存淘汰策略(LRU)?

答案
使用哈希表和双向链表实现最近最少使用(LRU)缓存。

示例代码

#include <list>
  #include <unordered_map>
    template<typename K, typename V>
      class LRUCache {
      public:
      explicit LRUCache(size_t capacity) : capacity(capacity) {}
      bool get(const K& key, V& value) {
      auto it = cache.find(key);
      if (it == cache.end()) return false;
      // 移到链表头部(最近使用)
      touch(it);
      value = it->second.first;
      return true;
      }
      void put(const K& key, const V& value) {
      auto it = cache.find(key);
      if (it != cache.end()) {
      // 更新值并移到头部
      it->second.first = value;
      touch(it);
      return;
      }
      // 插入新项
      if (cache.size() >= capacity) {
      // 淘汰最老项
      cache.erase(order.back());
      order.pop_back();
      }
      order.push_front(key);
      cache[key] = {value, order.begin()};
      }
      private:
      using CacheEntry = std::pair<V, typename std::list<K>::iterator>;
        size_t capacity;
        std::list<K> order;                  // 双向链表维护访问顺序
          std::unordered_map<K, CacheEntry> cache; // 哈希表存储键值对
            void touch(typename std::unordered_map<K, CacheEntry>::iterator it) {
              order.erase(it->second.second);
              order.push_front(it->first);
              it->second.second = order.begin();
              }
              };

原理

  • 双向链表维护访问顺序,头部为最近使用,尾部为最久未使用。
  • 哈希表快速查找键值对,值包含实际数据和链表迭代器。
  • 访问或插入时将元素移到链表头部,容量满时淘汰尾部元素。

二、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-16 20:37  gccbuaa  阅读(3)  评论(0)    收藏  举报