如何将unique_ptr对象传入静态库中的类作为参数
我之前也碰到过类似的情况——exe里的类用unique_ptr传参好好的,一到静态库就出问题。其实核心还是要抓住std::unique_ptr的独占特性,再结合静态库的编译/链接规则来调整,咱们一步步来:
1. 先把静态库中TScreen的构造函数写对
首先,静态库的头文件里,TScreen的构造函数要明确接收std::unique_ptr<TProcess>,推荐按值接收(比右值引用更简洁,编译器会自动处理move逻辑):
// 静态库头文件 TScreen.h class TProcess; // 前向声明就行,不用全定义 class TScreen { private: std::unique_ptr<TProcess> m_process; public: __fastcall TScreen(int a, std::unique_ptr<TProcess> i_process); // 别忘了声明析构函数,后面要用到 __fastcall ~TScreen(); };
然后到静态库的cpp实现文件里,必须包含TProcess的完整头文件,不然unique_ptr的析构会找不到符号,然后正确初始化成员:
// 静态库cpp文件 TScreen.cpp #include "TScreen.h" #include "TProcess.h" // 这里一定要包含完整定义,不能只前向声明 __fastcall TScreen::TScreen(int a, std::unique_ptr<TProcess> i_process) : m_process(std::move(i_process)) // 用std::move把所有权转交给成员变量 {} // 在这里实现析构函数,此时TProcess是完整类型,不会有链接问题 __fastcall TScreen::~TScreen() = default;
2. 调用方(exe里)必须正确转移所有权
std::unique_ptr是独占式智能指针,不能直接拷贝传递,所以调用构造函数的时候,必须用std::move()把所有权转移给TScreen:
// exe中的调用代码 #include "TScreen.h" #include "TProcess.h" int main() { // 创建一个TProcess的unique_ptr auto my_process = std::make_unique<TProcess>(); // 用std::move转移所有权给TScreen的构造函数 TScreen my_screen(123, std::move(my_process)); // 注意:此时my_process已经是空的了,所有权完全在my_screen的m_process里 return 0; }
3. 踩过的坑:类型完整性问题
这是静态库用unique_ptr最容易掉的坑——如果静态库的cpp文件里没有包含TProcess的完整定义,链接的时候会报类似undefined reference to std::unique_ptr<TProcess>::~unique_ptr()的错误。
原因是std::unique_ptr的析构函数需要知道TProcess的大小和析构逻辑,所以必须在有TProcess完整定义的地方生成析构函数(不管是TScreen的析构,还是unique_ptr自己的析构)。刚才的写法就是把TScreen的析构函数放在静态库cpp里实现,完美避开这个问题。
4. 最后检查链接和编译选项
确保你的exe项目已经正确链接了静态库,而且静态库和exe的编译选项要一致:比如都是Debug/Release模式,用同一个C标准(至少C11,因为unique_ptr是C++11才有的),不然可能会出现符号不兼容的问题。
内容的提问来源于stack exchange,提问作者Ravisangar

