C++ 智能指针shared_ptr和weak_ptr
- 技术
- 2024-04-03
- 443热度
- 0评论
C++智能指针
C++11 引入了 3 个智能指针类型用于解决指针管理问题,防止内存泄露:
- unique_ptr
- shared_ptr
- weak_ptr
智能指针是现代C++中管理动态分配内存的重要工具,它们通过自动管理资源的生命周期,帮助开发者避免常见的内存管理错误,如内存泄漏、野指针等。
unique_ptr
`unique_ptr` 是一种独占所有权的智能指针。当我们独占资源的所有权时,可以使用 `std::unique_ptr` 对资源进行管理。当 `unique_ptr` 对象离开其作用域时,它会自动释放所管理的资源。这是基于RAII(资源获取即初始化)思想的典型应用。
例如:
#include <iostream>
#include <memory>
int main() {
std::unique_ptr ptr(new int(42));
std::cout << *ptr << std::endl; // 输出42
return 0; // unique_ptr离开作用域,自动释放资源
}
`unique_ptr` 不能被复制,但可以被移动。这意味着它非常适合用于那些需要独占资源所有权的场景。
shared_ptr
`shared_ptr` 允许多个智能指针共享同一块内存资源。它使用引用计数来跟踪有多少个智能指针指向相同的资源。只有当最后一个 `shared_ptr` 被销毁时,资源才会被释放。
例如:
#include <iostream>
#include <memory>
int main() {
std::shared_ptr ptr1 = std::make_shared(42);
std::shared_ptr ptr2 = ptr1; // 共享所有权
std::cout << ptr2.use_count() << std::endl; // 输出2
std::cout << ptr1.use_count() << std::endl; // 输出2
return 0;
}
在这个例子中,`ptr1` 和 `ptr2` 都指向同一块内存资源。`use_count()` 方法返回当前指向该资源的 `shared_ptr` 的数量。当引用计数为 0 时,资源会被自动释放。
weak_ptr
`weak_ptr` 通常与 `shared_ptr` 一起使用,用于解决循环引用的问题。`weak_ptr` 不增加引用计数,只是观察 `shared_ptr` 的生命周期,不会阻止资源的释放。
例如:
#include <iostream>
#include <memory>
int main() {
std::shared_ptr ptr = std::make_shared(42);
std::weak_ptr weakPtr = ptr;
if (auto sharedPtr = weakPtr.lock()) {
std::cout << *sharedPtr << std::endl; // 输出42
}
return 0; // 在这里ptr被销毁
}
在这个例子中,`weakPtr` 是一个 `weak_ptr`,它指向由 `ptr` 管理的资源。`weakPtr.lock()` 方法尝试获取一个指向资源的 `shared_ptr`。如果资源仍然存在,它会返回一个有效的 `shared_ptr`;否则,它会返回一个空的 `shared_ptr`。
解决循环引用问题
循环引用是 `shared_ptr` 使用中常见的问题。例如,两个对象相互引用对方的 `shared_ptr`,会导致引用计数永不为零,从而导致内存泄漏。
例如:
#include <iostream>
#include <memory>
class B; // forward declaration
class A {
public:
std::shared_ptr bPtr; // shared_ptr to B
~A() {
std::cout << "A destructor called" << std::endl;
}
};
class B {
public:
std::shared_ptr aPtr; // shared_ptr to A
~B() {
std::cout << "B destructor called" << std::endl;
}
};
int main() {
std::shared_ptr aPtr = std::make_shared(); // create a shared_ptr to A
std::shared_ptr bPtr = std::make_shared(); // create a shared_ptr to B
aPtr->bPtr = bPtr; // assign bPtr to bPtr member of A
bPtr->aPtr = aPtr; // assign aPtr to aPtr member of B
return 0; // 由于循环引用,析构函数不会被调用,导致内存泄漏
}
在这个例子中,`A` 和 `B` 相互引用对方的 `shared_ptr`,导致引用计数永不为零,从而导致内存泄漏。
使用 `weak_ptr` 可以解决这个问题:
#include <iostream>
#include <memory>
class B; // forward declaration
class A {
public:
std::shared_ptr bPtr; // shared_ptr to B
~A() {
std::cout << "A destructor called" << std::endl;
}
};
class B {
public:
std::weak_ptr aWeakPtr; // weak_ptr to A
~B() {
std::cout << "B destructor called" << std::endl;
}
};
int main() {
std::shared_ptr aPtr = std::make_shared(); // create a shared_ptr to A
std::shared_ptr bPtr = std::make_shared(); // create a shared_ptr to B
aPtr->bPtr = bPtr; // assign bPtr to bPtr member of A
bPtr->aWeakPtr = aPtr; // assign aPtr to aWeakPtr member of B
return 0; // 现在A和B的析构函数都会被正确调用
}
在这个修改后的例子中,`B` 使用 `weak_ptr` 来引用 `A`,从而避免了循环引用问题。当 `aPtr` 和 `bPtr` 离开作用域时,它们的析构函数都会被正确调用,资源也会被正确释放。
总结
C++11 引入的智能指针是现代C++中管理动态内存的重要工具。`unique_ptr` 适用于独占资源所有权的场景,`shared_ptr` 适用于多个指针共享资源的场景,而 `weak_ptr` 则用于解决循环引用问题。通过合理使用这些智能指针,可以有效避免内存泄漏和其他资源管理问题,使代码更加安全和易于维护。