如何用Obj实例列表初始化std::vector<Obj*>?C++类构造问题
这个问题我之前也踩过坑,核心原因是std::initializer_list根本不能直接存引用类型——C++标准明确规定它的模板参数必须是对象类型(不能是引用或者带cv限定的引用),所以你写std::initializer_list<Obj&>才会触发那个「指针到引用非法」的错误。下面给你两种实用的解决方案:
方案一:改用
initializer_list<Obj*>(最简单直接) 把构造函数的参数改成存储指针的初始化列表,构造时手动传入对象地址即可:
class Foo { public: explicit Foo(std::initializer_list<Obj*> px) : fwds(px) {} // 直接用初始化列表初始化vector,省掉循环 private: std::vector<Obj*> fwds; }; // 使用方式: Foo f{&o1, &o3, &o4};
优点是代码改动极小、实现简单;缺点是需要手动加&,不符合你想要直接传实例的使用习惯。
方案二:用可变模板参数构造函数(完美匹配你的需求)
如果想完全保留Foo f{o1, o3, o4};的调用方式,推荐用可变模板参数的构造函数,它能自动接收任意数量的Obj实例,帮你把地址存入vector:
#include <type_traits> // 用于类型检查 class Foo { public: // 接受任意数量的Obj左值引用 template<typename... Args> explicit Foo(Args&... args) { // 强制所有参数都是Obj类型,避免传错对象 static_assert((std::is_same_v<std::decay_t<Args>, Obj> && ...), "All arguments must be instances of Obj"); fwds.reserve(sizeof...(args)); // 预分配空间,提升效率 (fwds.push_back(&args), ...); // 展开参数包,逐个存入对象地址 } // (可选)如果需要支持临时对象(比如 Foo f{Obj{}, Obj{}}),可以加这个版本 // 注意:临时对象生命周期短,建议用智能指针管理内存,避免悬空指针 // template<typename... Args> // explicit Foo(Args&&... args) { // static_assert((std::is_same_v<std::decay_t<Args>, Obj> && ...), // "All arguments must be instances of Obj"); // fwds.reserve(sizeof...(args)); // (fwds.push_back(new Obj(std::forward<Args>(args))), ...); // } private: std::vector<Obj*> fwds; }; // 使用方式完全符合你的预期: Obj o1{}; Obj o3{}; Obj o4{}; Foo f{o1, o3, o4};
这个方案的优势:
- 完全满足你直接传对象实例的需求,不用手动加
& - 通过
static_assert做类型校验,避免传入错误类型的对象 - 预分配空间减少vector的内存扩容开销
⚠️ 重要提醒:vector里存的是裸指针,必须保证所有传入的Obj实例的生命周期长于Foo对象,否则会出现悬空指针,导致未定义行为。如果需要管理对象生命周期,建议改用std::vector<std::unique_ptr<Obj>>或std::shared_ptr<Obj>替代裸指针。
内容的提问来源于stack exchange,提问作者quamrana
相关产品推荐
相关产品推荐

