对象创建的时机
- 尽早创建:
- 如果对象的生命周期贯穿程序运行的大部分,考虑在程序启动时创建,例如单例模式中的对象。按需创建:
在对象只在特定条件下需要时,延迟到确实需要时再创建(Lazy Initialization)。这可以减少内存占用和初始化开销。
std::shared_ptr<MyObject> obj = nullptr;
if (condition) {
obj = std::make_shared<MyObject>();
}
对象池:
如果某类对象被频繁创建和销毁,可以考虑使用对象池来减少内存分配和释放的开销。
class ObjectPool {
private:
std::vector<MyObject*> pool;
public:
MyObject* acquire() {
if (pool.empty()) return new MyObject();
MyObject* obj = pool.back();
pool.pop_back();
return obj;
}
void release(MyObject* obj) {
pool.push_back(obj);
}
};
智能指针:
使用std::shared_ptr或std::unique_ptr管理对象的生命周期,确保对象在适当的时机被销毁。
std::unique_ptr<MyObject> obj = std::make_unique<MyObject>();
对象销毁的时机
- 作用域控制:
局部变量会在超出作用域时自动销毁,无需手动管理资源。
void func() {
MyObject obj; // 在函数结束时自动销毁
}
RAII(资源获取即初始化):
利用构造函数获取资源,利用析构函数释放资源。例如,std::lock_guard保证互斥锁的安全释放。
std::mutex mtx;
{
std::lock_guard<std::mutex> lock(mtx); // 自动加锁和解锁
// 临界区代码
}
显式销毁:
如果对象在堆上分配,需要显式释放。
MyObject* obj = new MyObject();
delete obj; // 确保释放
避免悬挂指针:
如果对象销毁后仍有指针指向它,可能导致悬挂指针问题。使用智能指针或置空指针可以减少这种风险。
MyObject* obj = new MyObject();
delete obj;
obj = nullptr; // 避免悬挂指针
资源清理的集中管理:
使用容器或专用清理类集中管理对象,统一在程序退出时清理资源。
class ResourceManager {
private:
std::vector<std::unique_ptr<MyObject>> resources;
public:
void addResource(std::unique_ptr<MyObject> obj) {
resources.push_back(std::move(obj));
}
~ResourceManager() {
resources.clear();
}
};
其他注意事项
- 单例模式:
使用单例模式保证全局唯一的对象实例,但注意避免过度使用单例。
class Singleton {
private:
Singleton() {}
public:
static Singleton& getInstance() {
static Singleton instance;
return instance;
}
};
多线程环境中的安全:
在多线程程序中,确保对象创建和销毁的线程安全性,避免竞争条件。避免内存泄漏:
每个new必须对应一个delete,或通过智能指针自动管理资源。
析构函数中避免抛出异常:
如果析构函数抛出异常,可能导致未定义行为。
~MyObject() noexcept {
try {
// 清理资源
} catch (...) {
// 捕获所有异常以避免传播
}
}