首先解释指针和引用在C++中都用于间接访问变量,但它们有一些区别:
1. 指针是一个变量,它保存了另一个变量得内存地址;引用是另一个变量的别名,与原变量共享内存地址。
2. 指针可以被重新赋值,指向不同的变量;引用在初始化后不能更改,始终指向同一个变量。
3. 指针可以为nullptr,表示不指向任何变量;引用必须绑定到一个变量,不能为nullptr。
4. 使用指针需要对其进行解引用以获取或修改其指向的变量的值;引用可以直接使用,无需解引用。
在汇编层面来看 引用会被C++编译器当做const指针来进行操作。
RAII(Resource Acquisition Is Initialization)是由C++之父Bjarne Stroustrup提出的,中文翻译为资源获取即初始化,他说:使用局部对象来管理资源的技术称为资源获取即初始化;
这里的资源主要是指操作系统中有限的东西如指针内存、网络套接字、文件等等,局部对象是指存储在栈的对象,它的生命周期是由操作系统来管理的,无需人工介入。
在C/C++中,使用指针会出现各种问题,比如:
智能指针是一种可以自动管理内存的指针,它可以在不需要手动释放内存的情况下,确保对象正确地销毁。
这种指针可以显著降低程序中的内存泄露和悬空指针的风险。
智能指针的核心思想就是RAII
在C++中主要有两种智能指针
std::unique_ptr
std::shared_ptr
std::unique_ptr是一个独占所有权的智能指针,它保证指向的内存只能有一个unique_ptr拥有,不能共享所有权。
std::shared_ptr是一个共享所有权的智能指针,它允许多个shared_ptr指向同一个对象,当最后一个shared_ptr超出超出作用域时,所指向的内存才会被自动释放。
shared_ptr通过引用计数来记录有多少个shared_ptr共享同一个对象。
#include
#include
class MyClass {
public:
MyClass() { std::cout << "MyClass 构造函数\n"; }
~MyClass() { std::cout << "MyClass 析构函数\n"; }
void do_something() { std::cout << "MyClass::do_something() 被调用\n"; }
};
int main() {
{
std::shared_ptr ptr1 = std::make_shared();
{
std::shared_ptr ptr2 = ptr1; // 这里共享 MyClass 对象的所有权
ptr1->do_something();
ptr2->do_something();
std::cout << "ptr1 和 ptr2 作用域结束前的引用计数: " << ptr1.use_count() << std::endl;
} // 这里 ptr2 被销毁,但是 MyClass 对象不会被删除,因为 ptr1 仍然拥有它的所有权
std::cout << "ptr1 作用域结束前的引用计数: " << ptr1.use_count() << std::endl;
} // 这里 ptr1 被销毁,同时 MyClass 对象也会被删除,因为它是最后一个拥有对象所有权的 shared_ptr
return 0;
}
MyClass 构造函数
MyClass::do_something() 被调用
MyClass::do_something() 被调用
ptr1 和 ptr2 作用域结束前的引用计数: 2
ptr1 作用域结束前的引用计数: 1
MyClass 析构函数
double free 问题就是一块内存空间或者资源被释放两次。那么为什么会释放两次呢?
double free 可能是下面这些原因造成的:
shared_ptr
std::shared_ptr ptr;
make_shared
std::shared_ptr ptr = std::make_shared(42);
reset():释放当前 shared_ptr 的所有权,将其设置为 nullptr。如果当前 shared_ptr 是最后一个拥有对象所有权的智能指针,则会删除对象。
ptr.reset();
reset(T*):释放当前 shared_ptr 的所有权,并使其指向新的对象。如果当前 shared_ptr 是最后一个拥有对象所有权的智能指针,则会删除原对象。
ptr.reset(new int(42));
get():返回指向的对象的裸指针。注意,这个裸指针的生命周期由 shared_ptr 管理,你不应该使用它来创建另一个智能指针。
int* raw_ptr = ptr.get();
operator* 和 operator->:访问指向的对象。
int value = *ptr;
std::shared_ptr> vec_ptr = std::make_shared>();
vec_ptr->push_back(42);
use_count():返回当前 shared_ptr 的引用计数,即有多少个 shared_ptr 共享同一个对象。注意,use_count() 通常用于调试,不应该用于程序逻辑。
size_t count = ptr.use_count();
unique():检查当前 shared_ptr 是否是唯一拥有对象所有权的智能指针。等价于 use_count() == 1。
bool is_unique = ptr.unique();
swap(shared_ptr&):交换两个 shared_ptr 的内容。
std::shared_ptr ptr1 = std::make_shared(42);
std::shared_ptr ptr2 = std::make_shared(24);
ptr1.swap(ptr2);
operator bool():将 shared_ptr 隐式转换为 bool 类型,用于检查其是否为空。
if (ptr) {
std::cout << "ptr 不为空" << std::endl;
} else {
std::cout << "ptr 为空" << std::endl;
}
文章参考
作者: 编程指北
链接: https://csguide.cn/cpp/memory/shared_ptr.html#shared-ptr-%E7%9A%84%E4%BD%BF%E7%94%A8
来源: https://csguide.cn