You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用shared_ptr时程序崩溃,求代码问题分析及修复方案

问题分析与修复:shared_ptr错误构造导致程序崩溃

问题描述

在学习智能指针时,编写的程序在执行g1->outputs_.clear()时崩溃,但替换为g2->inputs_.clear()则正常,相关代码如下:

#include <QVector>
#include <memory>
using std::shared_ptr;
using std::make_shared;

class Node;
typedef shared_ptr<Node> NodePtr;

class Node {
  public:
    Node(){};

    NodePtr AddInput(NodePtr n){
        // 尝试将this转换为shared_ptr,添加到n->outputs_中
        NodePtr this_ptr(this);  

        if (!inputs_.contains(n)) {
            inputs_.append(n);
        }
        if (!n->outputs_.contains(this_ptr)) {
            n->outputs_.append(this_ptr);
        }
        return this_ptr;
    }

  public:
    QVector<NodePtr> inputs_;
    QVector<NodePtr> outputs_;
};


int main(){
    auto g1 = make_shared<Node>();
    auto g2 = make_shared<Node>();
    g2->AddInput(g1);
    g1->outputs_.clear();  // 程序在此处崩溃
    return 0;
}

崩溃原因

核心问题出在AddInput函数中NodePtr this_ptr(this);这一行:

  • g2是通过make_shared创建的,已经有一个shared_ptr实例在管理它的生命周期,维护着对应的引用计数。
  • 直接用裸指针this构造新的shared_ptr(this_ptr),会创建一个完全独立的智能指针实例,它的引用计数和g2的引用计数毫无关联。
  • 当执行g1->outputs_.clear()时,outputs_中的this_ptr会被销毁,此时这个独立的shared_ptr引用计数降为0,会直接释放g2指向的内存。
  • 但main函数中g2这个智能指针仍然存在,当main结束时,g2的引用计数降为0,会再次尝试释放已经被释放的内存,触发双重释放,导致程序崩溃。

而g2->inputs_.clear()正常的原因是:inputs_中存储的是来自参数的g1的智能指针,它和main中的g1共享同一个引用计数链,clear只会减少引用计数,不会让g1的引用计数降为0,因此不会提前释放内存。

修复方案

要正确获取管理当前对象的shared_ptr,需要让Node类继承std::enable_shared_from_this<Node>,然后通过shared_from_this()方法获取智能指针,这样得到的实例会和原来的shared_ptr共享引用计数。

修复后的代码:

#include <QVector>
#include <memory>
using std::shared_ptr;
using std::make_shared;

class Node;
typedef shared_ptr<Node> NodePtr;

// 继承enable_shared_from_this,用于获取当前对象的shared_ptr
class Node : public std::enable_shared_from_this<Node> {
  public:
    Node(){};

    NodePtr AddInput(NodePtr n){
        // 使用shared_from_this()替代直接用this构造
        NodePtr this_ptr = shared_from_this();  

        if (!inputs_.contains(n)) {
            inputs_.append(n);
        }
        if (!n->outputs_.contains(this_ptr)) {
            n->outputs_.append(this_ptr);
        }
        return this_ptr;
    }

  public:
    QVector<NodePtr> inputs_;
    QVector<NodePtr> outputs_;
};


int main(){
    auto g1 = make_shared<Node>();
    auto g2 = make_shared<Node>();
    g2->AddInput(g1);
    g1->outputs_.clear();  // 不再崩溃
    return 0;
}

注意事项

  • shared_from_this()只能在对象已经被shared_ptr管理的情况下调用,也就是必须先通过make_shared或shared_ptr构造函数创建对象的智能指针,之后才能调用该方法,否则会触发未定义行为。
  • 绝对不要直接用裸指针this构造shared_ptr,除非能确保该裸指针没有被其他shared_ptr管理,否则必然会导致引用计数混乱和内存错误。

内容的提问来源于stack exchange,提问作者Morry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 15:19:51