如何用std::vector<std::any>存储不同类型的std::unique_ptr?
问题解决:用std::any存储不同类型std::unique_ptr
一、std::any方案完全可行,修改编译报错的代码
编译报错的核心原因是std::unique_ptr仅支持移动语义(不可拷贝),直接传递给vector::push_back时,编译器无法自动完成unique_ptr到std::any的转换(std::any的拷贝构造要求存储类型可拷贝,而移动构造需要显式触发)。
修改后的可编译代码如下:
#include <vector> #include <any> #include <memory> class A { int val; }; class B { float val; }; int main() { std::vector<std::any> vec; // 方式1:用std::make_unique创建后,转移所有权到std::any auto a = std::make_unique<A>(); A& a_ref = *a; // 消费代码直接使用引用 vec.push_back(std::move(a)); // 方式2:直接在vector中构造std::any和unique_ptr,避免额外移动 auto b = std::make_unique<B>(); B& b_ref = *b; vec.emplace_back(std::move(b)); }
关键修改点:
- 使用
std::move显式转移unique_ptr的所有权到std::any中 - 或用
emplace_back直接在vector内部构造std::any,减少不必要的内存操作
二、其他轻量替代方案
如果不想依赖std::any,针对你"仅需自动清理对象、无需通过vector访问对象"的需求,还有两种更轻量化的选择:
1. 存储带自定义删除器的std::unique_ptr<void>
std::unique_ptr<void>本身无法自动销毁对象(因为不知道具体类型),但可以绑定自定义删除器,将销毁逻辑与对象指针绑定存储:
#include <vector> #include <memory> class A { int val; }; class B { float val; }; int main() { // 存储void指针+对应类型的删除器 std::vector<std::unique_ptr<void, void(*)(void*)>> vec; auto a = new A(); A& a_ref = *a; // 绑定A类型的销毁逻辑 vec.push_back(std::unique_ptr<void, void(*)(void*)>(a, [](void* p){ delete static_cast<A*>(p); })); auto b = new B(); B& b_ref = *b; // 绑定B类型的销毁逻辑 vec.push_back(std::unique_ptr<void, void(*)(void*)>(b, [](void* p){ delete static_cast<B*>(p); })); }
这种方案无需引入std::any,内存开销更小,完全满足自动清理的需求。
2. 存储销毁函数的std::vector<std::function<void()>>
直接将对象的销毁逻辑封装成函数,vector销毁时自动执行所有清理函数:
#include <vector> #include <functional> #include <memory> class A { int val; }; class B { float val; }; int main() { std::vector<std::function<void()>> cleanup_list; auto a = new A(); A& a_ref = *a; // 封装A的销毁逻辑 cleanup_list.emplace_back([a](){ delete a; }); auto b = new B(); B& b_ref = *b; // 封装B的销毁逻辑 cleanup_list.emplace_back([b](){ delete b; }); }
vector生命周期结束时,所有lambda会被依次执行,自动完成对象清理,逻辑简单直接。
总结
std::any方案完全可行,只需正确处理unique_ptr的移动语义- 若追求轻量高效,带自定义删除器的
unique_ptr<void>或销毁函数列表是更优选择
内容的提问来源于stack exchange,提问作者catluna
相关产品推荐
相关产品推荐

