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

从C#调用C++库遇偶发崩溃:临时对象生命周期是否合法?

问题描述

我在从C#调用一个不受我控制的C库时遇到了偶发崩溃问题。该C库的内部代码大致如下:

#include <string>
#include <memory>

class Holder {
    public:
    static std::shared_ptr<Holder> create() {
        return std::make_shared<Holder>();
    }

    const std::string& getRef() {
        return value;
    }

    private:
    std::string value;
};

extern "C" void getRef(std::string& v) {
    auto h = Holder::create();
    v = h->getRef();
}

我通过P/Invoke调用getRef方法,未使用特殊封送处理。请问这种写法能保证正常运行吗?h会在getRef方法结束时超出作用域,但它的成员value的引用被保留并传递出去,在C#端访问该引用时是否仍然有效?

问题分析与解答

这种写法完全不能保证正常运行,C#端访问该引用时必然会触发无效内存访问,你遇到的偶发崩溃就是这个原因导致的。

核心原因拆解:

  • 在C++的getRef函数中,h是局部的std::shared_ptr<Holder>,函数执行完毕时h会离开作用域,对应的Holder对象引用计数归零,随即被销毁。
  • Holder对象销毁时,其成员value(std::string类型)会被析构,底层内存会被释放或标记为可复用状态。
  • 你通过v = h->getRef()将value的引用赋值给参数v,但.NET的P/Invoke默认没有针对std::string的内置封送逻辑,直接传递引用本质上是传递内存地址。当Holder对象销毁后,该地址指向的内存已经无效,C#端访问时会触发未定义行为——可能直接崩溃、读取到垃圾数据,甚至在内存未被覆盖的偶然情况下看似正常,这就是“偶发崩溃”的由来。

总结:h销毁后,value的内存已被回收,C#端拿到的内存地址指向无效内存,访问它必然出问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 09:52:38