使用 vector

在 C++ 中,将
std::shared_ptr存储在
std::vector等容器中是一种常见的做法,尤其在需要共享对象所有权、避免内存泄漏或实现多所有者语义时。但使用时需要注意一些关键点,以确保程序的性能、安全性和可维护性。
1. 为什么用 vector<shared_ptr<T>>
?
使用
vector<shared_ptr<T>>而不是
vector<T>或
vector<unique_ptr<T>>通常有以下原因:
-
共享所有权:多个地方需要持有同一个对象的引用,
shared_ptr
自动管理生命周期。 -
多态性支持:存储基类指针时,
shared_ptr<Base>
可以指向派生类对象,实现多态。 - 避免深拷贝:对于大对象或不可拷贝类型,用指针避免复制开销。
-
安全的动态生命周期管理:对象在不再被任何
shared_ptr
引用时自动释放。
2. 使用 vector<shared_ptr<T>>
的注意事项
✅ 正确初始化 shared_ptr
不要将裸指针多次构造
shared_ptr,否则会导致重复释放。推荐使用
make_shared:
std::vector<std::shared_ptr<MyClass>> vec; vec.push_back(std::make_shared<MyClass>(arg1, arg2));
避免这样写:
MyClass* ptr = new MyClass(); vec.push_back(std::shared_ptr<MyClass>(ptr)); vec.push_back(std::shared_ptr<MyClass>(ptr)); // 错误!两个 shared_ptr 独立管理同一指针
✅ 注意循环引用问题
如果
shared_ptr指向的对象内部又持有对自身的
shared_ptr引用(或通过容器间接引用),可能造成循环引用,导致内存泄漏。
解决方法:在适当位置使用
std::weak_ptr打破循环。
class Node {
public:
std::shared_ptr<Node> parent;
std::vector<std::shared_ptr<Node>> children;
// 如果 children 反向引用 parent,应考虑用 weak_ptr
};✅ 性能考量:内存局部性 vs 灵活性
vector<shared_ptr<T>>中存储的是指针,实际对象分散在堆上,可能造成:
- 缓存命中率低(访问频繁时性能不如
vector<T>
) - 额外的控制块开销(每个
shared_ptr
都有引用计数)
建议:
- 如果不需要共享所有权,优先使用
vector<T>
或vector<unique_ptr<T>>
- 如果对象大或不可拷贝,再考虑
shared_ptr
✅ 容器操作的安全性
vector的扩容(如
push_back导致
reallocation)会复制或移动
shared_ptr,但这是安全的,因为
shared_ptr支持拷贝和移动语义。
vec.push_back(ptr); // 增加引用计数,安全 vec.erase(it); // 删除元素,引用计数减一,对象可能被释放
注意:删除
vector中的元素或清空容器时,
shared_ptr被销毁,引用计数减一,若归零则自动释放对象。
✅ 多线程环境下的注意点
虽然
shared_ptr的引用计数是线程安全的(多个线程增加/减少引用安全),但多个线程同时访问同一个
shared_ptr对象本身(如赋值、拷贝)需要外部同步。
// 多线程操作同一个 shared_ptr 实例时要加锁 std::shared_ptr<MyClass> sp = std::make_shared<MyClass>(); std::vector<std::shared_ptr<MyClass>> vec; // 线程1 vec.push_back(sp); // 安全:拷贝 sp,增加引用计数 // 线程2 vec.push_back(sp); // 安全:同上 // 但如果多个线程修改同一个 shared_ptr 变量,则不安全
3. 推荐实践
-
优先使用
make_shared
:更高效(减少内存分配次数),更安全。 -
避免不必要的 shared_ptr:如果只是唯一所有者,用
unique_ptr
更轻量。 -
注意对象生命周期:确保
shared_ptr
不会意外延长对象生命周期。 - 结合 weak_ptr 防止循环引用:尤其是在树、图结构中。
-
考虑替代方案:
vector<unique_ptr<T>>
:唯一所有权,性能更好vector<T>
:值语义,适合小对象- 使用对象池 + 索引:避免频繁动态分配
基本上就这些。
vector<shared_ptr<T>>是强大且安全的工具,但要用对场景,注意引用计数、循环引用和性能影响。










