一句话结论
std::vector<T&> 之类的写法是非法的,根本原因:引用不是对象,而标准容器存的是对象。
核心原因
1. 引用不是对象,没有自己的存储
引用只是已有对象的别名,它没有独立的内存、没有地址、没有 sizeof。容器在堆上分配内存来存放元素,而引用根本没有"可以被存进去的东西"。
cpp
int a = 1;
int& r = a;
sizeof(r); // 得到的是 int 的大小,不是"引用"的大小
&r; // 得到的是 a 的地址,不是引用自身的地址
2. 引用不可重新绑定(不可赋值)
引用一旦初始化就永远指向那个对象,赋值操作会修改被引用的对象,而不是让引用指向别处。容器的很多操作(insert、erase、sort、swap)都要求元素可赋值、可移动,引用做不到。
cpp
int a = 1, b = 2;
int& r = a;
r = b; // 实际是 a = b,r 仍然引用 a,无法让它引用 b
3. 引用不能默认构造
resize、reserve 加元素等操作需要类型能默认构造一个"空"元素,但引用必须在定义时立即绑定到对象,不存在"空引用"。
4. 无法形成指向引用的指针 / 取引用地址
容器底层靠指针遍历元素(T*),而 C++ 不允许 T&*(指向引用的指针),标准要求 allocator_traits<T>::pointer 是合法的指针类型,引用不满足。
标准是怎么规定的
C++ 标准对容器元素类型有一组统一要求(Container 概念),包括:
- 可拷贝 / 可移动构造
- 可赋值
- 可析构(
Erase、CopyInsertable、MoveInsertable等)
引用类型全部不满足,所以在类型层面直接被禁止。
想要"存引用"该怎么办
| 方案 | 写法 | 说明 |
|---|---|---|
| 存包装引用 | std::vector<std::reference_wrapper<T>> |
推荐,语义上就是"可重绑的引用" |
| 存指针 | std::vector<T*> |
传统做法,但可能为 nullptr,需注意生命周期 |
| 存智能指针 | std::vector<std::shared_ptr<T>> |
需要共同管理生命周期时使用 |
小结
一句话:容器需要"能复制、能赋值、能默认构造、有存储"的对象,而引用只具备别名语义,不具备对象语义 ,所以装不进去。需要间接引用时,用 reference_wrapper 或指针即可。