为什么 ref_count 在 shared_ptr 实现中是 int*
Why ref_count in shared_ptr implementation is int*
我见过 shared_ptr 的几个实现,例如 here。他们都将 ref_count
声明为 int*
。我不明白如果它只是一个 int
,我们会失去什么。谢谢!
template <class T>
class shared_ptr {
T* ptr;
int* ref_count;
/**
* Initializes the ref count used for tracking the usage.
*/
void initialize_ref_count() {
if (ref_count != nullptr)
return;
try {
ref_count = new int;
*ref_count = 1;
}
catch (std::bad_alloc& e) {
std::cerr << "Memory allocation error: " << e.what();
}
}
}
正如您在提供的实现中看到的那样(in your link),当共享指针是复制构造或复制分配,指向引用计数器 (ref_count
) 的指针在管理同一指针的所有实例之间共享:
// Copy constructor
shared_ptr(const shared_ptr& copy) {
ptr = copy.ptr;
ref_count = copy.ref_count; // see here
if (ref_count != nullptr) {
++(*ref_count);
}
}
// Assignment operator
shared_ptr& operator=(const shared_ptr& copy) {
ptr = copy.ptr;
ref_count = copy.ref_count; // see here
if (ref_count != nullptr) {
++(*ref_count);
}
return *this;
}
这样,那个共享指针的所有实例,引用同一个内存位置来跟踪引用计数器,最后一个shared_ptr
将能够知道是否需要清理(delete
分配的内存):
~shared_ptr() {
--(*ref_count);
if (*ref_count == 0) {
delete ref_count;
ref_count = nullptr;
delete ptr;
ptr = nullptr;
}
}
免责声明
为简单起见,此答案基于 OP 提供的示例。 shared_ptr
实现比示例中的实现复杂得多(考虑原子性、竞争条件等...)。
首先,在其他地方分享一些东西,你需要把它放在其他人可以访问的地方。正如@Igor Tandetnik 所指出的。因此 动态存储持续时间 的对象可以很好地完成这项工作。 静态存储持续时间 和动态初始化的对象也可以做到这一点,但该对象将存在于程序的其余部分,这是我们不想要的。
其次,shared_ptr
比那更复杂。典型的 shared_ptr
会引用 控制块 。这个控制块通常包含:
- 对象的共享引用数,
- 有问题的对象或指向该对象的指针,
- 以及对控制块的弱引用数。
为了线程安全,共享引用计数和弱引用计数通常由原子类型持有。
编辑:参见@Passer 的评论。
我见过 shared_ptr 的几个实现,例如 here。他们都将 ref_count
声明为 int*
。我不明白如果它只是一个 int
,我们会失去什么。谢谢!
template <class T>
class shared_ptr {
T* ptr;
int* ref_count;
/**
* Initializes the ref count used for tracking the usage.
*/
void initialize_ref_count() {
if (ref_count != nullptr)
return;
try {
ref_count = new int;
*ref_count = 1;
}
catch (std::bad_alloc& e) {
std::cerr << "Memory allocation error: " << e.what();
}
}
}
正如您在提供的实现中看到的那样(in your link),当共享指针是复制构造或复制分配,指向引用计数器 (ref_count
) 的指针在管理同一指针的所有实例之间共享:
// Copy constructor
shared_ptr(const shared_ptr& copy) {
ptr = copy.ptr;
ref_count = copy.ref_count; // see here
if (ref_count != nullptr) {
++(*ref_count);
}
}
// Assignment operator
shared_ptr& operator=(const shared_ptr& copy) {
ptr = copy.ptr;
ref_count = copy.ref_count; // see here
if (ref_count != nullptr) {
++(*ref_count);
}
return *this;
}
这样,那个共享指针的所有实例,引用同一个内存位置来跟踪引用计数器,最后一个shared_ptr
将能够知道是否需要清理(delete
分配的内存):
~shared_ptr() {
--(*ref_count);
if (*ref_count == 0) {
delete ref_count;
ref_count = nullptr;
delete ptr;
ptr = nullptr;
}
}
免责声明
为简单起见,此答案基于 OP 提供的示例。 shared_ptr
实现比示例中的实现复杂得多(考虑原子性、竞争条件等...)。
首先,在其他地方分享一些东西,你需要把它放在其他人可以访问的地方。正如@Igor Tandetnik 所指出的。因此 动态存储持续时间 的对象可以很好地完成这项工作。 静态存储持续时间 和动态初始化的对象也可以做到这一点,但该对象将存在于程序的其余部分,这是我们不想要的。
其次,shared_ptr
比那更复杂。典型的 shared_ptr
会引用 控制块 。这个控制块通常包含:
- 对象的共享引用数,
- 有问题的对象或指向该对象的指针,
- 以及对控制块的弱引用数。
为了线程安全,共享引用计数和弱引用计数通常由原子类型持有。
编辑:参见@Passer 的评论。