1.概要
- shared_ptr和weak_ptr的reset实验
- 用weak_ptr化解shared_ptr交叉引用的问题
- std::unique_ptr<int> p2 = std::move(p1); // p1 变为空,p2 拥有对象的所有权
2.代码
#include <iostream>
using namespace std;
template<typename T>
void fun(weak_ptr<T> wp) {
if (wp.expired()) {
cout << "Object has been released\n";
}
else {
cout << "Object not released\n";
}
}
namespace t1 {
void test() {
cout << "--- Release with shared_ptr -----------------------------\n";
shared_ptr<int> sh_ptr = make_shared<int>();
weak_ptr<int> wp(sh_ptr);
fun<int>(wp);//结果:Object not released
sh_ptr.reset();
fun<int>(wp);//结果:Object has been released
}
}
namespace t2 {
void test() {
cout << "--- Release with weak_ptr -----------------------------\n";
shared_ptr<int> sh_ptr = make_shared<int>();
weak_ptr<int> wp(sh_ptr);
fun<int>(wp);//结果:Object not released
//sh_ptr.reset();
wp.reset();
fun<int>(wp);//结果:Object has been released
}
}
namespace t3 {
class B;
class A
{
public:
A() {
cout << "A constructor call\n";
}
~A() {
cout << "A Destructor call\n";
}
shared_ptr<B> sh_ptr_b;
};
class B
{
public:
B() {
cout << "A constructor call\n";
}
~B() {
cout << "A Destructor call\n";
}
shared_ptr<A> sh_ptr_a;
};
void test() {
//这个实验会让交叉引用发生,导致对象无法析构
cout << "--- Cross references cannot be destructed -----------------------------\n";
shared_ptr<A> sh_ptr_a = make_shared<A>();
shared_ptr<B> sh_ptr_b = make_shared<B>();
cout << "ptr_a use_count: " << sh_ptr_a.use_count() << endl;
cout << "ptr_b use_count: " << sh_ptr_b.use_count() << endl;
sh_ptr_a.get()->sh_ptr_b = sh_ptr_b;
sh_ptr_b.get()->sh_ptr_a = sh_ptr_a;
//这里因为发生了交叉引用,所以对象最终不会析构,会发生内存泄露
cout << "ptr_a use_count: " << sh_ptr_a.use_count() << endl;
cout << "ptr_b use_count: " << sh_ptr_b.use_count() << endl;
}
/*
运行结果:最后没有调用析构函数
A constructor call
A constructor call
ptr_a use_count: 1
ptr_b use_count: 1
ptr_a use_count: 2
ptr_b use_count: 2
*/
}
namespace t4 {
class B;
class A
{
public:
A() {
cout << "A constructor call\n";
}
~A() {
cout << "A Destructor call\n";
}
//shared_ptr<B> sh_ptr_b;
//这是把shared_ptr<B>换成了weak_ptr<B>就化解了交叉引用
weak_ptr<B> sh_ptr_b;
};
class B
{
public:
B() {
cout << "A constructor call\n";
}
~B() {
cout << "A Destructor call\n";
}
shared_ptr<A> sh_ptr_a;
};
void test() {
//交叉引用的问题会得到解决
cout << "--- Cross reference problem solved -----------------------------\n";
shared_ptr<A> sh_ptr_a = make_shared<A>();
shared_ptr<B> sh_ptr_b = make_shared<B>();
cout << "ptr_a use_count: " << sh_ptr_a.use_count() << endl;
cout << "ptr_b use_count: " << sh_ptr_b.use_count() << endl;
sh_ptr_a.get()->sh_ptr_b = sh_ptr_b;
sh_ptr_b.get()->sh_ptr_a = sh_ptr_a;
//这里weak_ptr<B>会对这种引用做相应的处理所以 最终对象可以析构 不会发生内存泄露
cout << "ptr_a use_count: " << sh_ptr_a.use_count() << endl;
cout << "ptr_b use_count: " << sh_ptr_b.use_count() << endl;
}
/*
测试结果:调用了析构函数
A constructor call
A constructor call
ptr_a use_count: 1
ptr_b use_count: 1
ptr_a use_count: 2
ptr_b use_count: 1
A Destructor call
A Destructor call*/
}
int main()
{
t1::test();
t2::test();
t3::test();
t4::test();
cout << "Hello World!\n";
}
3.运行结果
--- Release with shared_ptr -----------------------------
Object not released
Object has been released
--- Release with weak_ptr -----------------------------
Object not released
Object has been released
--- Cross references cannot be destructed -----------------------------
A constructor call
A constructor call
ptr_a use_count: 1
ptr_b use_count: 1
ptr_a use_count: 2
ptr_b use_count: 2
--- Cross reference problem solved -----------------------------
A constructor call
A constructor call
ptr_a use_count: 1
ptr_b use_count: 1
ptr_a use_count: 2
ptr_b use_count: 1
A Destructor call
A Destructor call
4.关联知识
1.c++有几种智能指针?对比说明,举例
在C++中,主要有四种智能指针,它们是:std::auto_ptr(已被废弃)、std::unique_ptr、std::shared_ptr 和 std::weak_ptr。下面将分别介绍这些智能指针的特点和使用场景。
1. std::auto_ptr(已废弃)
std::auto_ptr 是C++98和C++03标准库中的智能指针,但由于其设计存在缺陷(如拷贝语义),已在C++11中被废弃,并在C++17中被完全移除。
- 特点:
- 管理单个对象的所有权。
- 拷贝时会转移所有权,导致源指针变为空。
- 不适合用于容器或在多线程环境中使用。
- 示例:
std::auto_ptr<int> p1(new int(10)); std::auto_ptr<int> p2 = p1; // p1 变为空,p2 拥有对象的所有权
2. std::unique_ptr
std::unique_ptr 是C++11引入的智能指针,用于替代 std::auto_ptr。
- 特点:
- 独占对象的所有权,不能复制,只能通过移动语义转移所有权。
- 支持删除器(deleter),可以自定义删除逻辑。
- 适用于管理单个对象的生命周期。
- 示例:
std::unique_ptr<int> p1(new int(10)); std::unique_ptr<int> p2 = std::move(p1); // p1 变为空,p2 拥有对象的所有权
3. std::shared_ptr
std::shared_ptr 也是C++11引入的智能指针,用于共享对象的所有权。
- 特点:
- 多个
std::shared_ptr实例可以共享同一个对象。 - 使用引用计数来管理对象的生命周期,当最后一个
std::shared_ptr被销毁时,对象才会被删除。 - 支持删除器(deleter)。
- 线程安全(引用计数的增减是原子的)。
- 多个
- 示例:
std::shared_ptr<int> p1(new int(10)); std::shared_ptr<int> p2 = p1; // p1 和 p2 共享同一个对象
4. std::weak_ptr
std::weak_ptr 是为了配合 std::shared_ptr 而设计的,用于解决循环引用问题。
- 特点:
- 不能独立拥有对象,必须从一个
std::shared_ptr或另一个std::weak_ptr创建。 - 不影响对象的引用计数,不会阻止对象被销毁。
- 可以用于检查对象是否还存在,并获取一个
std::shared_ptr来访问对象。
- 不能独立拥有对象,必须从一个
- 示例:
std::shared_ptr<int> sp = std::make_shared<int>(10); std::weak_ptr<int> wp = sp; // 不会增加引用计数 if (auto locked = wp.lock()) { // 检查对象是否还存在 // locked 是一个 shared_ptr,可以安全访问对象 }
对比总结
- 所有权管理:
std::unique_ptr:独占所有权,不可共享。std::shared_ptr:共享所有权,通过引用计数管理。std::weak_ptr:不管理所有权,仅用于引用std::shared_ptr。
- 生命周期:
std::unique_ptr:生命周期由单个unique_ptr管理。std::shared_ptr:生命周期由所有shared_ptr共享管理。std::weak_ptr:不影响生命周期管理。
- 适用场景:
std::unique_ptr:适用于需要独占所有权的场景。std::shared_ptr:适用于需要共享所有权的场景。std::weak_ptr:适用于需要引用std::shared_ptr但不增加引用计数的场景,常用于解决循环引用问题。
选择适当的智能指针,可以帮助你更好地管理动态内存和资源,避免内存泄漏和其他资源管理问题。
2.c++有几种智能指针?对比说明
在C++中,智能指针是一种管理动态分配内存的类模板,用于自动处理内存释放,防止内存泄漏。C++11标准引入了三种主要的智能指针:std::unique_ptr、std::shared_ptr 和 std::weak_ptr。下面是对这三种智能指针的对比说明:
1. std::unique_ptr
- 独占所有权:
std::unique_ptr拥有对其管理对象的独占所有权。同一时间只能有一个std::unique_ptr拥有该对象。 - 不可复制:由于其独占性,
std::unique_ptr不允许复制(拷贝构造函数和赋值操作符被删除)。但可以通过std::move转移所有权。 - 销毁对象:当
std::unique_ptr超出作用域或被销毁时,它所管理的对象也会被自动销毁(调用delete)。 - 定制删除器:可以指定自定义的删除器来控制对象的销毁方式。
2. std::shared_ptr
- 共享所有权:
std::shared_ptr允许多个智能指针共享同一个对象。对象会在最后一个std::shared_ptr被销毁时自动释放。 - 引用计数:内部使用引用计数机制来跟踪有多少个
std::shared_ptr共享同一个对象。 - 可复制:
std::shared_ptr支持复制操作,每个复制的智能指针都会增加引用计数。 - 线程安全:引用计数的增减操作是线程安全的(尽管整体的
std::shared_ptr使用场景仍需注意线程安全)。 - 定制删除器:同样支持自定义删除器。
3. std::weak_ptr
- 弱引用:
std::weak_ptr是一种弱引用,不能独立拥有对象,它必须从一个std::shared_ptr或另一个std::weak_ptr创建。 - 不增加引用计数:
std::weak_ptr不影响对象的生命周期,即不会增加引用计数,因此不会阻止对象被销毁。 - 解决循环引用:主要用于解决
std::shared_ptr间的循环引用问题,防止内存泄漏。 - 访问对象:需要通过
lock()方法获取一个std::shared_ptr来访问对象,如果对象已被销毁,lock()将返回一个空的std::shared_ptr。
对比总结
- 所有权:
std::unique_ptr:独占所有权。std::shared_ptr:共享所有权。std::weak_ptr:弱引用,无所有权。
- 生命周期管理:
std::unique_ptr:超出作用域即销毁对象。std::shared_ptr:基于引用计数,最后一个shared_ptr销毁时对象被销毁。std::weak_ptr:不影响对象生命周期。
- 复制行为:
std::unique_ptr:不可复制,仅可移动。std::shared_ptr:可复制,引用计数增加。std::weak_ptr:可复制,不影响引用计数。
- 用途:
std::unique_ptr:适用于明确需要独占所有权的场景。std::shared_ptr:适用于需要共享所有权的场景。std::weak_ptr:适用于解决shared_ptr循环引用问题,或实现弱引用。
通过合理使用这三种智能指针,可以有效地管理动态内存,减少内存泄漏和悬挂指针的问题。
3.c++有几种智能指针?对比说明,使用表格
在C++中,智能指针是一种用于自动管理动态分配内存的类模板。C++11标准引入了三种主要的智能指针:std::unique_ptr、std::shared_ptr 和 std::weak_ptr。此外,还有一种在C++98和C++03标准中存在的智能指针std::auto_ptr,但由于其设计缺陷已在C++11中被废弃,并在C++17中被完全移除。下面是关于这四种智能指针的对比说明,以表格形式呈现:
| 智能指针类型 | 所有权 | 复制性 | 引用计数 | 主要用途 | 备注 |
|---|---|---|---|---|---|
std::auto_ptr | 独占所有权 | 转移所有权 | 不使用 | 已被废弃 | 在C++11中被弃用,C++17中被移除 |
std::unique_ptr | 独占所有权 | 不可复制,仅可移动 | 不使用 | 管理单个对象的生命周期 | 替代std::auto_ptr |
std::shared_ptr | 共享所有权 | 可复制 | 使用 | 允许多个指针共享同一对象 | 通过引用计数管理生命周期 |
std::weak_ptr | 弱引用,无所有权 | 可复制 | 不使用 | 解决std::shared_ptr循环引用问题 | 不影响对象的引用计数 |
对比说明
-
所有权:
std::auto_ptr和std::unique_ptr拥有独占所有权,这意味着在任何时候只有一个智能指针可以指向特定对象。std::shared_ptr允许多个智能指针共享同一对象的所有权。std::weak_ptr是弱引用,不拥有对象的所有权。
-
复制性:
std::auto_ptr在复制时会转移所有权,导致源指针变为空。std::unique_ptr不可复制,仅可通过移动语义转移所有权。std::shared_ptr可复制,每次复制都会增加引用计数。std::weak_ptr可复制,但复制不会影响对象的引用计数。
-
引用计数:
std::auto_ptr不使用引用计数。std::unique_ptr同样不使用引用计数。std::shared_ptr使用引用计数来管理对象的生命周期,当引用计数变为0时,对象被销毁。std::weak_ptr不使用引用计数,但可以与std::shared_ptr配合使用来检查对象是否仍然存在。
-
主要用途:
std::auto_ptr(已被废弃)原本用于自动管理动态分配对象的生命周期。std::unique_ptr适用于需要独占所有权的场景。std::shared_ptr适用于需要共享所有权的场景。std::weak_ptr主要用于解决std::shared_ptr之间的循环引用问题。
-
备注:
std::auto_ptr由于设计缺陷已在C++11中被废弃,并在C++17中被完全移除。std::unique_ptr是C++11中引入的智能指针,用于替代std::auto_ptr。std::shared_ptr和std::weak_ptr也是C++11中引入的智能指针,用于更复杂的内存管理场景。
通过上述表格和对比说明,可以清晰地了解每种智能指针的特点和用途。
本文通过实例展示了C++中shared_ptr和weak_ptr在释放对象和解决交叉引用问题上的作用,以及如何使用weak_ptr避免内存泄露。


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



