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

使用std::shared_ptr时C++程序出现段错误的排查求助

问题根源分析

你的代码出现段错误的核心原因是悬空指针导致的未定义行为,具体出在ctrVar函数的实现和lambda捕获逻辑上:

1. 临时对象的生命周期问题

ctrVar函数里的代码是:

return std::make_shared<ConstrainedVariable<I, O>>(ConstrainedVariable<I, O>(refVar, refCurve));

这里先创建了一个临时的ConstrainedVariable对象,再用这个临时对象初始化shared_ptr管理的堆对象(调用拷贝构造)。临时对象会在该行代码执行完毕后立即销毁。

2. Lambda捕获的this指向悬空

在ConstrainedVariable的构造函数中,你创建的lambda捕获了当前对象的this:

constraint = action([this](){this->applyConstraint();});

这个this指向的是临时对象的地址。当临时对象销毁后,lambda里的this就变成了悬空指针。后续当refVar触发更新调用这个lambda时,访问this->_refVar或this->_refCurve都会读取已释放的内存,进而出现段错误,调试中看到的nan就是内存乱读的结果。

3. 普通指针版本正常的原因

当你用栈上对象auto _c = ConstrainedVariable<...>(...)时,_c的生命周期和main函数一致,lambda捕获的this指向的是栈上的有效对象,所以不会出现悬空指针问题。


修复方案

有两种直接的修复方式:

方式一:直接在make_shared中构造对象,避免临时对象

修改ctrVar函数,直接传递构造参数给make_shared,跳过临时对象的创建:

template<class I, class O>
std::shared_ptr<ConstrainedVariable<I, O>> ctrVar(VariablePtr<I> refVar, Curve<I, O> refCurve){
  return std::make_shared<ConstrainedVariable<I, O>>(std::move(refVar), std::move(refCurve));
};

这样make_shared会直接在堆上构造ConstrainedVariable对象,lambda捕获的this指向堆上的有效对象,生命周期由shared_ptr管理,不会悬空。

方式二:禁用拷贝构造,从源头避免错误

为了防止再写出类似的错误代码,可以禁用ConstrainedVariable的拷贝构造和赋值,强制使用移动语义:

template<class I, class O>
class ConstrainedVariable : private Variable<O> {
  // ... 现有成员 ...
  // 禁用拷贝构造和拷贝赋值
  ConstrainedVariable(const ConstrainedVariable&) = delete;
  ConstrainedVariable& operator=(const ConstrainedVariable&) = delete;
  // 允许移动构造和移动赋值
  ConstrainedVariable(ConstrainedVariable&&) = default;
  ConstrainedVariable& operator=(ConstrainedVariable&&) = default;
};

此时如果再写出创建临时对象拷贝的代码,编译器会直接报错,提前阻止错误发生。


验证修复

修改ctrVar后运行代码,会得到正常输出:

0
0
1
0.841471

v->set(1)会触发ConstrainedVariable的applyConstraint,正确计算sin(1)的值,不会出现段错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 13:10:03