关于std::map中std::shared_ptr<void>的使用疑问
代码示例
#include <iostream> #include <vector> #include <string> #include <map> #include <sstream> using namespace std; typedef std::map<std::string, std::shared_ptr<void>> M; typedef std::vector<std::string> S; void build_word_tree_from_sentences(const S& sentence_list, M& root) { for (const auto& sentence : sentence_list) { std::string word; std::stringstream ss(sentence); M* base = &root; while (ss >> word) { auto found = base->find(word); if (found == base->end()) { base->insert(std::make_pair(word, std::make_shared<M>())); } auto b = base->find(word)->second; base = std::static_pointer_cast<M>(b).get(); } } } int main() { S sentence_list = {"Hello word", "Hello there"}; M tree; build_word_tree_from_sentences(sentence_list, tree); }
问题
我理解std::shared_ptr的作用:它管理指针的存储,并通过自动释放已分配的内存实现有限的垃圾回收。但我不清楚为何要将其声明为std::shared_ptr<void>,查阅相关资料后仍未解决困惑。
解答
核心原因是绕开C++递归类型定义的限制:
- 这里的
M是表示单词树节点的类型,每个节点需要存储指向子节点(同样是M类型)的智能指针。如果直接把M定义成std::map<std::string, std::shared_ptr<M>>,编译器会报错——因为在定义M的时候,M本身还不是完整类型,无法用于声明shared_ptr<M>。 std::shared_ptr<void>在这里起到类型擦除的作用:它可以持有任意动态分配对象的shared_ptr,同时保留正确的析构逻辑(shared_ptr内部会保存对象的析构器,所以即使是shared_ptr<void>,也能在销毁时正确释放底层的M对象,不会出现内存泄漏)。- 代码里通过
std::static_pointer_cast<M>把shared_ptr<void>转换回原本的shared_ptr<M>,就能正常访问子节点的map结构,实现树的递归构建。
简单说,这是C++里实现递归树形结构的一种妥协方案,用类型擦除避开编译器对不完整类型的限制。
内容的提问来源于stack exchange,提问作者Franco
相关产品推荐
相关产品推荐

