std::shared_ptr学习笔记
基本概念
std::shared_ptr是C++标准库提供的一种智能指针,用于共享式拥有资源。它可以共享资源的所有权,确保资源在最后一个引用被销毁时自动释放。std::shared_ptr采用引用计数的方式管理资源,每个std::shared_ptr对象都会维护一个引用计数,记录有多少个对象共享了相同的资源。
内部原理
std::shared_ptr的内部原理基于引用计数。当一个std::shared_ptr对象拥有某个资源时,会在堆上分配一个控制块(control block),其中包含一个指向共享资源的指针以及一个引用计数。当有新的std::shared_ptr对象拥有相同的资源时,它们会共享同一个控制块,并且增加引用计数。当一个std::shared_ptr对象销毁时,会减少引用计数,当引用计数为0时,表示没有对象再共享资源,资源会被释放。
应用场景
- 共享资源管理:
std::shared_ptr适用于需要多个对象共享同一个资源的情况,如多个对象共享一个大型数据结构或文件。 - 循环引用处理:在一些情况下,对象之间存在循环引用,导致无法释放资源。使用
std::shared_ptr可以解决这个问题,通过使用std::weak_ptr来打破循环引用。 - STL容器元素管理:
std::shared_ptr可以作为STL容器(如std::vector、std::list等)的元素类型,方便管理容器中的对象生命周期。
示例代码
#include <memory>
#include <iostream>
int main() {
// 创建一个std::shared_ptr对象
std::shared_ptr<int> ptr1(new int(42));
// 创建另一个std::shared_ptr对象,共享相同的资源
std::shared_ptr<int> ptr2 = ptr1;
// 输出共享资源的值
std::cout << *ptr1 << std::endl; // 输出 42
std::cout << *ptr2 << std::endl; // 输出 42
return 0;
}
使用技巧
- 避免循环引用:循环引用会导致资源无法释放,可以使用
std::weak_ptr来打破循环引用。 - 优先使用
std::make_shared:使用std::make_shared函数可以减少动态内存分配的开销,提高性能(见附一)。 - 注意线程安全:
std::shared_ptr的引用计数是线程安全的,但多线程修改同一份资源可能会导致竞态条件,需要额外的同步措施来保证线程安全。
示例代码
#include <memory>
#include <thread>
#include <iostream>
void foo(std::shared_ptr<int> ptr) {
// 在多线程环境中使用shared_ptr需要注意线程安全
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Value: " << *ptr << std::endl;
}
int main() {
std::shared_ptr<int> ptr = std::make_shared<int>(42);
std::thread t1(foo, ptr);
std::thread t2(foo, ptr);
t1.join();
t2.join();
return 0;
}
实战案例
管理动态分配的资源
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<int> ptr1(new int(42));
std::shared_ptr<int> ptr2 = ptr1;
std::cout << *ptr1 << std::endl; // 输出 42
std::cout << *ptr2 << std::endl; // 输出 42
return 0;
}
STL容器中的应用
#include <memory>
#include <vector>
#include <iostream>
int main() {
std::vector<std::shared_ptr<int>> vec;
for (int i = 0; i < 5; ++i) {
vec.push_back(std::make_shared<int>(i));
}
for (const auto& ptr : vec) {
std::cout << *ptr << " ";
}
std::cout << std::endl;
return 0;
}
这些示例展示了std::shared_ptr的基本用法、内部原理、常见应用场景和使用技巧,以及实战案例。
附一
使用std::make_shared函数可以减少动态内存分配的开销主要有两个原因:
- 减少内存分配次数:
std::make_shared会在单次内存分配中同时分配控制块(用于存储引用计数和指向资源的指针)和对象所需的内存空间。而直接使用new创建std::shared_ptr时,会先分配控制块,然后再分配对象的内存空间。使用std::make_shared可以将这两步合并为一步,减少了内存分配的次数。 - 减少控制块的内存开销:
std::make_shared会为新对象分配一个更大的内存块,该内存块中包含对象的内存空间和控制块,而不是单独分配控制块和对象的内存空间。这种方法可以减少控制块的内存开销,因为多个std::shared_ptr对象可以共享同一个控制块,这样一来,只有一个控制块需要内存对齐和额外的管理信息。
2356

被折叠的 条评论
为什么被折叠?



