C++ 调用 Go 方法的字符串传递问题及解决方案
摘要:C++调用Go方法时,字符串参数的内存管理需要由Go侧进行深度值拷贝。
现象
在一个APP技术项目中,子进程按请求加载Go的ServiceModule,将需要拉起的ServiceModule信息传递给Go的Loader,存在C++调用Go方法,传递字符串的场景。
方案验证时,发现有奇怪的将std::string对象的内容传递给Go方法后,在Go方法协程中取到的值与预期不一致。
经过一段时间的分析和验证,终于理解问题产生的原因并给出解决方案,现分享如下。
背景知识
Go有自己的内存回收GC机制,通过make等申请的内存不需要手动释放。
C++中为std::string变量赋值新字符串后,.c_str()和.size()的结果会联动变化,尤其是.c_str()指向的地址也有可能变化。
go build -buildmode=c-shared .生成的.h头文件中定义了C++中Go的变量类型的定义映射关系,比如GoString、GoInt等。其中GoString实际是一个结构体,包含一个字符指针和一个字符长度。
原理及解释
通过代码示例方式解释具体现象及原因,详见注释
C++侧代码:
Go侧代码:
Go侧代码通过-buildmode=c-shared的方式生成libgoloader.so及libgoloader.h供C++编译运行使用
程序执行结果:
结论
结论:C++调用Go方法时,字符串参数的内存管理需要由Go侧进行深度值拷贝。即参数三的处理方式
原因:传入的字符串GoString,实际是一个结构体,第一个成员p是一个char*指针,第二个成员n是一个int长度。
在C++代码中,任何对成员p的char*指针的操作,都将直接影响到Go中的string对象的值。
只有通过单独的内存空间开辟,进行独立内存管理,才可以避免C++中的指针操作对Go的影响。
ps:不在C++中进行内存申请释放的原因是C++无法感知Go中何时才能真的已经没有对象引用,无法找到合适的时间点进行内存释放。
本文分享自华为云社区《C++调用Go方法的字符串传递问题及解决方案》,原文作者:王芾。
版权声明: 本文为 InfoQ 作者【华为云开发者社区】的原创文章。
原文链接:【http://xie.infoq.cn/article/34fec9687a51fc38df1ec1b81】。文章转载请联系作者。
评论