C++引用计数通过std::shared_ptr实现,利用控制块管理强/弱引用计数,确保对象在无所有者时自动释放;其核心机制为原子操作增减计数,避免内存泄漏,但需警惕循环引用问题。

C++的引用计数机制,在我看来,是现代C++内存管理中一个非常核心且优雅的解决方案,它允许对象在被多个地方共享时,能够自动地管理其生命周期。简单来说,就是通过追踪有多少个“所有者”指向一个对象,当这个计数归零时,对象就会被自动销毁。这大大减轻了手动管理内存的负担,也降低了内存泄漏和悬空指针的风险。
引用计数的核心原理其实并不复杂,它为每个被管理的对象维护一个引用计数器。
当一个智能指针(比如
std::shared_ptr
std::shared_ptr
当我们谈到C++中的引用计数,
std::shared_ptr
std::shared_ptr
这个控制块通常包含以下几个关键部分:
立即学习“C++免费学习笔记(深入)”;
std::shared_ptr
std::weak_ptr
std::weak_ptr
每次你创建一个
std::shared_ptr
std::shared_ptr
std::shared_ptr
#include <iostream>
#include <memory>
class MyObject {
public:
MyObject() { std::cout << "MyObject constructed!" << std::endl; }
~MyObject() { std::cout << "MyObject destructed!" << std::endl; }
void doSomething() { std::cout << "Doing something..." << std::endl; }
};
int main() {
std::shared_ptr<MyObject> ptr1 = std::make_shared<MyObject>(); // 强引用计数 = 1
std::cout << "ptr1 ref count: " << ptr1.use_count() << std::endl;
{
std::shared_ptr<MyObject> ptr2 = ptr1; // 强引用计数 = 2
std::cout << "ptr2 ref count: " << ptr2.use_count() << std::endl;
ptr2->doSomething();
} // ptr2超出作用域,强引用计数 = 1
std::cout << "ptr1 ref count after ptr2 scope: " << ptr1.use_count() << std::endl;
// ptr1 也超出作用域,强引用计数 = 0,MyObject 被析构
return 0;
}这里值得一提的是
std::make_shared
new
std::shared_ptr
引用计数虽然强大,但它并非银弹,在实际开发中确实会遇到一些挑战,其中最臭名昭著的莫过于“循环引用”(Circular Reference)。
1. 循环引用 (Circular Reference)
这是引用计数最常见的陷阱。当两个或多个对象通过
std::shared_ptr
#include <iostream>
#include <memory>
class B; // 前向声明
class A {
public:
std::shared_ptr<B> b_ptr;
A() { std::cout << "A constructed!" << std::endl; }
~A() { std::cout << "A destructed!" << std::endl; }
};
class B {
public:
std::shared_ptr<A> a_ptr;
B() { std::cout << "B constructed!" << std::endl; }
~B() { std::cout << "B destructed!" << std::endl; }
};
void create_circular_reference() {
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->b_ptr = b; // A持有B的shared_ptr
b->a_ptr = a; // B持有A的shared_ptr
// 此时,a和b的强引用计数都为2。
// 当create_circular_reference函数结束时,a和b的shared_ptr局部变量被销毁,
// 它们的强引用计数都变为1。因为不为0,所以A和B都不会被析构,造成内存泄漏。
}
int main() {
create_circular_reference();
std::cout << "End of main." << std::endl; // 你会发现A和B的析构函数没有被调用
return 0;
}在这个例子中,
a
b
b
a
a
b
shared_ptr
a
b
shared_ptr
避免方法:使用 std::weak_ptr
std::weak_ptr
std::shared_ptr
std::weak_ptr
std::weak_ptr
std::shared_ptr
lock()
lock()
std::shared_ptr
将上面例子中的
b->a_ptr
std::weak_ptr<A> a_ptr;
// ... (A和B的定义,B中的a_ptr改为std::weak_ptr<A>)
class B {
public:
std::weak_ptr<A> a_ptr; // 改为weak_ptr
B() { std::cout << "B constructed!" << std::endl; }
~B() { std::cout << "B destructed!" << std::endl; }
};
void create_correct_reference() {
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->b_ptr = b; // A持有B的shared_ptr (强引用)
b->a_ptr = a; // B持有A的weak_ptr (弱引用)
// 当函数结束时,a和b的局部shared_ptr失效。
// 此时,B对A的引用是弱引用,不影响A的强引用计数。
// A的强引用计数变为0,A被析构。
// A被析构后,a->b_ptr失效,B的强引用计数也变为0,B被析构。
}
int main() {
create_correct_reference();
std::cout << "End of main." << std::endl; // A和B的析构函数会被调用
return 0;
}2. 性能开销
引用计数机制的每次增减操作都需要原子性地执行,以确保多线程环境下的正确性。原子操作通常比普通操作有更高的开销。此外,每个
shared_ptr
避免方法:
std::make_shared
std::unique_ptr
std::unique_ptr
shared_ptr
shared_ptr
3. 线程安全
std::shared_ptr
shared_ptr
避免方法:
shared_ptr
shared_ptr
C++的内存管理策略多种多样,引用计数只是其中一种,每种都有其适用场景和权衡。
1. 手动内存管理 (new
delete
new
delete
delete
delete
delete
2. 独占所有权 (std::unique_ptr
std::unique_ptr
unique_ptr
unique_ptr
shared_ptr
unique_ptr
shared_ptr
shared_ptr
unique_ptr
shared_ptr
3. 垃圾回收 (Garbage Collection, GC)
4. 自定义内存分配器 (Custom Allocators)
std::shared_ptr
std::unique_ptr
总的来说,引用计数 (
std::shared_ptr
std::weak_ptr
std::unique_ptr
std::shared_ptr
以上就是C++内存管理基础中引用计数机制原理解析的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号