两种创建 shared_ptr
的方式
-
通过构造函数直接构造
shared_ptr
:std::shared_ptr<MyClass> ptr(new MyClass(10));
- 内存分配:
- 两次内存分配:一次为对象内存 (
new MyClass(10)
),一次为控制块内存。
- 两次内存分配:一次为对象内存 (
- 灵活性:
- 允许自定义删除器:
std::shared_ptr<MyClass> ptr(new MyClass(10), custom_deleter);
- 允许自定义删除器:
- 内存释放:
- 当共享引用计数(shared count)降为零时,调用删除器释放对象内存。
- 当弱引用计数(weak count)降为零时,释放控制块内存。
- 内存分配:
-
使用
std::make_shared
构造shared_ptr
:std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>(10);
- 内存分配:
- 一次内存分配:对象和控制块一起分配。
- 效率:
- 更高效,减少了内存分配次数。
- 内存释放:
- 当共享引用计数(shared count)降为零时,释放对象和控制块内存。
- 内存分配:
在有弱指针 (weak_ptr
) 使用时的内存释放时机
-
通过构造函数直接构造
shared_ptr
:- 当共享引用计数(shared count)降为零时:
- 对象内存被释放,但控制块内存保留,直到弱引用计数(weak count)也降为零。
- 当弱引用计数(weak count)降为零时:
- 控制块内存被释放。
- 当共享引用计数(shared count)降为零时:
-
使用
std::make_shared
构造shared_ptr
:- 当共享引用计数(shared count)降为零时:
- 对象会被调用析构函数,但内存暂时不会被释放,只有等到共享引用计数和弱引用计数同时为零时才会释放对象内存和控制块内存。
- 当共享引用计数(shared count)降为零时:
详细比较
-
内存分配:
- 构造函数:
- 分配两次内存,一次给对象,一次给控制块。
make_shared
:- 一次内存分配,对象和控制块在同一块内存中。
- 构造函数:
-
内存释放:
- 构造函数:
- 共享引用计数为零时释放对象内存。
- 弱引用计数为零时释放控制块内存。
make_shared
:- 共享引用计数和弱引用计数同时为零时同时释放对象和控制块内存。
- 构造函数:
-
灵活性和异常安全性:
- 构造函数:
- 允许自定义删除器,适用于需要特殊资源管理的场景。
- 在对象和控制块分开分配时,构造过程中抛出异常可能导致内存泄漏。
make_shared
:- 不允许自定义删除器,但在大多数情况下提供了更高效的内存管理。
- 提供更好的异常安全性,因为对象和控制块一起分配。
- 构造函数:
示例代码
通过构造函数直接构造 shared_ptr
和 weak_ptr
#include <memory>
#include <iostream>
class MyClass {
public:
MyClass(int value) : value(value) {
std::cout << "MyClass constructed\n";
}
~MyClass() {
std::cout << "MyClass destroyed\n";
}
private:
int value;
};
int main() {
std::shared_ptr<MyClass> ptr(new MyClass(10));
std::weak_ptr<MyClass> weakPtr = ptr;
std::cout << "Shared Count: " << ptr.use_count() << "\n"; // 应为1
// Reset shared_ptr to test destruction
ptr.reset();
std::cout << "Shared Count after reset: " << ptr.use_count() << "\n"; // 应为0
// weak_ptr still keeps control block alive
if (auto shared = weakPtr.lock()) {
std::cout << "Weak pointer still valid.\n";
} else {
std::cout << "Weak pointer expired.\n";
}
return 0;
}
使用 std::make_shared
构造 shared_ptr
和 weak_ptr
#include <memory>
#include <iostream>
class MyClass {
public:
MyClass(int value) : value(value) {
std::cout << "MyClass constructed\n";
}
~MyClass() {
std::cout << "MyClass destroyed\n";
}
private:
int value;
};
int main() {
std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>(10);
std::weak_ptr<MyClass> weakPtr = ptr;
std::cout << "Shared Count: " << ptr.use_count() << "\n"; // 应为1
// Reset shared_ptr to test destruction
ptr.reset();
std::cout << "Shared Count after reset: " << ptr.use_count() << "\n"; // 应为0
// weak_ptr still keeps control block alive
if (auto shared = weakPtr.lock()) {
std::cout << "Weak pointer still valid.\n";
} else {
std::cout << "Weak pointer expired.\n";
}
return 0;
}