完整教程:C++面试题及详细答案100道( 81-90 )
《前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。

文章目录
一、本文面试题目录
81. 如何实现一个简单的内存泄漏检测器?
答案:
通过重载全局new和delete操作符,记录分配和释放的内存块。
示例代码:
#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保护观察者列表的读写操作。 attach和detach操作加锁确保原子性。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_head和m_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();
}
};
原理:
- 双向链表维护访问顺序,头部为最近使用,尾部为最久未使用。
- 哈希表快速查找键值对,值包含实际数据和链表迭代器。
- 访问或插入时将元素移到链表头部,容量满时淘汰尾部元素。

浙公网安备 33010602011771号