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

C++中通过shared_ptr存储右值引用引发段错误的问题

问题分析与解决方案

核心错误:ostream运算符无限递归

你的段错误并非来自shared_ptr的无效引用,而是operator<<的无限递归调用:

std::ostream& operator<<(std::ostream& os, const Tensor& x) {
    std::cout << x << "\n"; // 这里会再次调用本运算符,无限递归
    return os;
}

这段代码会不断调用自身,导致栈溢出,表现为段错误。

修复步骤

1. 修复输出运算符

把输出逻辑改为直接打印data成员,避免递归:

std::ostream& operator<<(std::ostream& os, const Tensor& x) {
    os << x.data;
    return os;
}

2. 完善Tensor的语义与运算符重载

当前的运算符只接受右值引用,限制了使用场景。可以调整运算符参数,让它同时支持左值和右值,同时确保临时对象的生命周期被shared_ptr正确接管:

修正后的完整代码:

#include <memory>
#include <iostream>

class Tensor;
class Op{
public:
    std::shared_ptr<Tensor> lhs;
    std::shared_ptr<Tensor> rhs;
    Op(std::shared_ptr<Tensor> lhs) : lhs(lhs) {};
    Op(std::shared_ptr<Tensor> lhs, std::shared_ptr<Tensor> rhs) : lhs(lhs) , rhs(rhs) {};
};

class Tensor{
public:
    std::shared_ptr<Op> op;
    int data;
    // 普通构造
    Tensor(int y): data(y) {}
    // 移动构造
    Tensor(Tensor&& lhs) noexcept 
        : data(std::move(lhs.data))
        , op(std::move(lhs.op)){}
    // 拷贝构造(可选,根据需求添加)
    Tensor(const Tensor& lhs)
        : data(lhs.data)
        , op(lhs.op){}
};

// 修复后的输出运算符
std::ostream& operator<<(std::ostream& os, const Tensor& x) {
    os << x.data;
    return os;
}

// 调整运算符参数,支持左值和右值
Tensor operator*(Tensor lhs, Tensor rhs){
    // 将传入的对象(可能是移动来的临时对象)转为shared_ptr
    std::shared_ptr<Tensor> lhs_ = std::make_shared<Tensor>(std::move(lhs));
    std::shared_ptr<Tensor> rhs_ = std::make_shared<Tensor>(std::move(rhs));
    Tensor ret(11);
    // 存储父节点引用
    ret.op = std::make_shared<Op>(lhs_, rhs_);
    return ret;
}

int main()
{
    Tensor a = Tensor(3) * Tensor(4); 
    
    std::cout << a.data << "\n";
    // 现在可以正常访问
    std::cout << *a.op->lhs << "\n";
    std::cout << *a.op->rhs << "\n";

    return 0;
}

关键说明

  • 生命周期管理:通过std::make_shared<Tensor>(std::move(lhs))将临时对象或左值对象移动到shared_ptr管理的内存中,确保这些对象不会被提前销毁,后续通过op->lhs/op->rhs访问时始终有效。
  • 运算符灵活性:把运算符参数改为Tensor lhs而非Tensor&& lhs,这样编译器会自动对左值调用拷贝构造,对右值调用移动构造,既支持链式调用(a+b)*(c+d),也支持左值相乘。
  • 移动语义:保留移动构造函数,避免不必要的拷贝,提升性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 11:55:31