面试题答案
一键面试内存管理策略
- 智能指针
- std::unique_ptr:适用于对象所有权唯一的场景。例如在一个图形渲染项目中,每个
Mesh
对象(用于存储3D模型数据)可以由一个std::unique_ptr
来管理。Mesh
对象通常有复杂的内存结构,包含顶点数据、索引数据等。
std::unique_ptr<Mesh> mesh = std::make_unique<Mesh>(vertexData, indexData);
- std::shared_ptr:当多个对象可能需要共享同一个资源的所有权时使用。比如在一个游戏开发项目中,多个
GameObject
可能共享同一个Texture
资源。
std::shared_ptr<Texture> texture = std::make_shared<Texture>("texture.png"); GameObject obj1(texture); GameObject obj2(texture);
- std::weak_ptr:用于解决
std::shared_ptr
的循环引用问题。例如在一个双向链表结构中,节点A持有节点B的std::shared_ptr
,节点B持有节点A的std::weak_ptr
,防止循环引用导致内存泄漏。
struct Node; using NodePtr = std::shared_ptr<Node>; using WeakNodePtr = std::weak_ptr<Node>; struct Node { int data; NodePtr next; WeakNodePtr prev; };
- std::unique_ptr:适用于对象所有权唯一的场景。例如在一个图形渲染项目中,每个
- RAII(Resource Acquisition Is Initialization)原则:利用对象的生命周期来管理资源。智能指针就是RAII的典型应用。当一个包含智能指针成员的对象被销毁时,智能指针会自动释放其所指向的资源,确保内存不会泄漏。例如,在一个数据库连接类中:
class DatabaseConnection {
public:
DatabaseConnection() {
// 初始化数据库连接
}
~DatabaseConnection() {
// 关闭数据库连接
}
private:
std::unique_ptr<DatabaseHandle> handle;
};
指针类型的选择
- 原始指针:
- 使用场景:在函数内部的临时变量,并且生命周期明确且简单。例如在遍历一个数组时,用于获取数组元素的地址。
int arr[10]; int* ptr = arr; for (int i = 0; i < 10; ++i) { std::cout << *ptr << std::endl; ptr++; }
- 注意事项:原始指针需要手动管理内存,容易导致内存泄漏和悬空指针问题,所以在复杂的对象层次结构和多线程环境中应尽量避免使用,除非有非常明确的理由。
- 智能指针:如上述内存管理策略中所述,根据对象所有权和资源共享情况选择合适的智能指针类型。
线程同步
- 互斥锁(Mutex):用于保护共享资源,防止多个线程同时访问。例如在一个多线程的文件写入操作中,多个线程可能需要向同一个文件写入数据,使用互斥锁来确保同一时间只有一个线程可以写入。
std::mutex fileMutex;
void writeToFile(const std::string& data) {
std::lock_guard<std::mutex> lock(fileMutex);
std::ofstream file("output.txt", std::ios::app);
file << data << std::endl;
}
- 读写锁(Read - Write Lock):适用于读多写少的场景。在一个多线程的缓存系统中,多个线程可能频繁读取缓存数据,偶尔有线程更新缓存。读操作可以并发执行,而写操作需要独占访问。
std::shared_mutex cacheMutex;
std::unordered_map<int, int> cache;
void readFromCache(int key) {
std::shared_lock<std::shared_mutex> lock(cacheMutex);
auto it = cache.find(key);
if (it != cache.end()) {
// 处理读取到的数据
}
}
void writeToCache(int key, int value) {
std::unique_lock<std::shared_mutex> lock(cacheMutex);
cache[key] = value;
}
- 条件变量(Condition Variable):用于线程间的同步通信。在一个生产者 - 消费者模型中,生产者线程生产数据并放入队列,消费者线程从队列中取出数据。当队列为空时,消费者线程等待,直到生产者线程向队列中放入数据并通知条件变量。
std::mutex queueMutex;
std::condition_variable queueCV;
std::queue<int> dataQueue;
void producer() {
for (int i = 0; i < 10; ++i) {
std::unique_lock<std::mutex> lock(queueMutex);
dataQueue.push(i);
lock.unlock();
queueCV.notify_one();
}
}
void consumer() {
while (true) {
std::unique_lock<std::mutex> lock(queueMutex);
queueCV.wait(lock, [] { return!dataQueue.empty(); });
int data = dataQueue.front();
dataQueue.pop();
lock.unlock();
// 处理消费的数据
}
}
在大型C++项目中,合理选择内存管理策略、指针类型,并正确使用线程同步机制,能有效提高程序的安全性、性能和可维护性。