掌握std::vector<T*>
vs std::vector<T&>
是 理解指针与引用在容器中区别和适用场景的关键点。
下面将从语法、底层原理、能否使用、典型用途、安全性与扩展等方面进行 详细对比讲解,并辅以示例,帮助吃透这个核心概念。
一、基本对比结论
比较项 | std::vector<T*> | std::vector<T&> |
---|---|---|
是否合法 | ✅ 合法 | ❌ 非法,引用不能作为容器元素类型 |
典型用途 | 指向对象的指针集合 | ❌ 不能直接使用 |
是否可以为空 | ✅ 可存 nullptr | ❌ 不存在空引用 |
需要额外注意生命周期吗 | ✅ 是 | ❌ 引用不能存储,强制绑定生命周期 |
替代方案 | 使用智能指针如 std::unique_ptr<T> | 用 std::reference_wrapper<T> 包装引用 |
二、为什么 std::vector<T&>
不合法?
引用在 C++ 中不是对象,而是变量的别名。STL 容器要求元素可以 复制、移动、存储、管理生命周期,引用显然不满足这些要求。
编译错误示例:
std::vector<int&> vec; // ❌ 错误:引用不是对象,不能拷贝
三、推荐方案一:使用指针
#include <vector>
#include <iostream>
struct Obj {
int val;
Obj(int v) : val(v) {}
void print() { std::cout << val << "\n"; }
};
int main() {
Obj a(1), b(2), c(3);
std::vector<Obj*> vec;
vec.push_back(&a);
vec.push_back(&b);
vec.push_back(&c);
for (auto* p : vec)
p->print(); // 输出 1 2 3
}
优势:
- 可存储任意对象的地址
- 可以为
nullptr
- 灵活指向不同对象
注意:
- 生命周期需自己管理,不能使用已经被释放的对象地址
四、推荐方案二:使用 std::reference_wrapper<T>
虽然不能直接用 vector<T&>
,但 C++ 提供了 std::reference_wrapper<T>
,它本质上是一个对引用的封装类,可以模拟引用集合。
#include <vector>
#include <functional> // std::reference_wrapper
#include <iostream>
int main() {
int a = 1, b = 2, c = 3;
std::vector<std::reference_wrapper<int>> vec;
vec.push_back(a);
vec.push_back(b);
vec.push_back(c);
for (auto& ref : vec)
std::cout << ref.get() << "\n"; // 输出 1 2 3
vec[0].get() = 10; // 修改原始变量 a
std::cout << "a = " << a << "\n"; // 输出 a = 10
}
优势:
- 实现引用语义存储
- 可与
std::bind
,std::function
协同使用 - 保持原始变量的引用属性
注意:
- 仍需保证被引用对象的生命周期大于容器
get()
访问封装的引用
五、使用场景总结
需求 | 推荐做法 |
---|---|
需要引用对象,但不能复制 | 使用 std::reference_wrapper<T> |
需要控制对象生命周期 | 使用 std::unique_ptr<T> |
存指针集合并自由操作 | 使用 std::vector<T*> |
存值并自动管理 | 使用 std::vector<T> 直接存值 |
六、进阶对比:vector<T*>
vs vector<unique_ptr<T>>
类型 | 是否自动释放 | 语义 | 推荐使用场景 |
---|---|---|---|
T* | ❌ 否,需手动 delete | 指针 | 简单引用外部对象 |
unique_ptr<T> | ✅ 自动析构 | 拥有权转移 | 管理生命周期的资源集合 |
std::vector<std::unique_ptr<MyClass>> vec;
vec.push_back(std::make_unique<MyClass>());
七、结语:选择建议
- 想要传值修改原始变量 → 用
std::reference_wrapper<T>
- 想要灵活指向不同对象 → 用裸指针或智能指针集合
- ❌ 不要尝试
vector<T&>
—— C++ 不允许