类中定义智能指针时容易踩的坑
写C++代码时,很多人在类里用智能指针觉得省心,不用手动delete。但实际用起来,稍不注意就出问题。比如某个成员变量是std::shared_ptr,在构造函数里忘了初始化,结果一用就崩溃。
这种情况就像你买了个新电饭煲,说明书说要先加水再通电,你倒好,插上就按煮饭,跳闸了才想起来没加水。代码也一样,智能指针虽然能自动管理内存,但它本身也需要正确“启动”。
未初始化导致的空指针访问
看下面这个例子:
class ImageProcessor {
private:
std::shared_ptr<Image> m_image;
public:
void process() {
if (m_image->isValid()) { // 这里崩了
// 处理图片
}
}
};这段代码编译没问题,运行到process()就挂。因为m_image是空的,压根没指向任何对象。解决办法是在构造函数里给它一个初始值:
ImageProcessor() : m_image(std::make_shared<Image>()) {}循环引用让内存无法释放
另一个常见问题是两个类互相持有对方的shared_ptr。比如父节点保存子节点的shared_ptr,子节点又保存父节点的shared_ptr。这就像两个人互相欠钱,谁也不肯先还,最后债务永远结不清。
结果就是对象销毁时,引用计数始终不为零,内存一直占着。这时候得换weak_ptr:
class Node {
public:
std::shared_ptr<Node> parent;
std::weak_ptr<Node> child; // 避免循环
};weak_ptr不会增加引用计数,只在需要时临时升级成shared_ptr,用完就丢,干净利落。
自定义删除器用错场景
有时候资源不是new出来的,比如用fopen打开的文件句柄,想用unique_ptr管理。这时候必须指定删除器,否则默认delete会出问题。
auto file_deleter = [](FILE* f) {
if (f) fclose(f);
};
std::unique_ptr<FILE, decltype(file_deleter)> fp(fopen("data.txt", "r"), file_deleter);如果不写删除器,fclose不会被调,文件一直开着,可能造成句柄泄露。这就像出门忘了关煤气,隐患很大。
类里定义智能指针,核心是搞清楚生命周期和所有权。别图省事随便套个shared_ptr,不然后期排错花的时间比写代码还多。