C++无自动垃圾回收,依赖手动管理易致内存泄漏、悬挂指针和重复释放;智能指针通过RAII机制将资源管理绑定对象生命周期,unique_ptr实现独占所有权,离开作用域自动释放,避免泄漏;shared_ptr通过引用计数允许多方共享,计数归零时释放资源;weak_ptr打破循环引用,与shared_ptr协同,不增引用计数,用lock()安全访问对象,确保内存安全回收。

C++的内存回收,说白了,它自己可没有Java或者Python那种自带的“垃圾回收器”来帮你清理门户。它依赖的是一套更原始,也更强大的机制:程序员手动管理。但手动管理嘛,就容易出岔子。这就是为什么智能指针会出现,它们通过一种叫RAII(Resource Acquisition Is Initialization,资源获取即初始化)的哲学,把内存的分配和释放跟对象的生命周期牢牢绑定在一起。简单来说,一旦你用智能指针管理了一个资源,当这个智能指针自己寿终正寝(比如离开作用域)的时候,它就会自动帮你把关联的内存也清理掉。这大大提升了内存的安全性,也让我们的代码健壮性上了一个台阶,避免了那些恼人的内存泄漏和悬挂指针。
要有效管理C++的内存,尤其是动态分配的内存,核心策略就是将资源管理与对象生命周期同步。传统上,我们使用
new
delete
智能指针正是为了解决这些问题而生的。它们是C++标准库提供的一组模板类,封装了原始指针,并在自身生命周期结束时自动调用
delete
delete
说实话,C++的内存管理,就像一把双刃剑,强大但容易伤到自己。最常见的几个坑,我个人感觉是:
立即学习“C++免费学习笔记(深入)”;
new
delete
delete
return
delete
delete
智能指针,特别是
std::unique_ptr
std::shared_ptr
std::unique_ptr
unique_ptr
unique_ptr
unique_ptr
unique_ptr
std::shared_ptr
shared_ptr
shared_ptr
shared_ptr
它们把手动管理变成了自动管理,程序员的心智负担减轻了,代码的稳定性自然就上去了。
unique_ptr
shared_ptr
这两种智能指针是C++11引入的重头戏,它们在内存管理上扮演的角色截然不同,理解它们的区别是高效使用C++的关键。
std::unique_ptr
unique_ptr
unique_ptr
unique_ptr
unique_ptr
unique_ptr
std::vector<std::unique_ptr<MyObject>>
举个例子:
#include <iostream>
#include <memory> // 包含 unique_ptr 和 make_unique
class MyResource {
public:
MyResource() { std::cout << "MyResource created\n"; }
~MyResource() { std::cout << "MyResource destroyed\n"; }
void doSomething() { std::cout << "Doing something with MyResource\n"; }
};
std::unique_ptr<MyResource> createResource() {
return std::make_unique<MyResource>(); // 返回一个unique_ptr,所有权转移
} // MyResource在这里不会被销毁,因为所有权转移了
void processResource(std::unique_ptr<MyResource> res) {
res->doSomething();
} // res离开作用域,MyResource被销毁
int main() {
std::unique_ptr<MyResource> ptr1 = createResource();
ptr1->doSomething();
// std::unique_ptr<MyResource> ptr2 = ptr1; // 编译错误:unique_ptr不能拷贝
std::unique_ptr<MyResource> ptr2 = std::move(ptr1); // 可以移动
if (!ptr1) {
std::cout << "ptr1 is now empty after move.\n";
}
ptr2->doSomething();
// 也可以直接传递给函数,函数接收所有权
processResource(std::move(ptr2)); // MyResource在这里被销毁
// ptr2现在也空了
return 0;
}std::shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
weak_ptr
#include <iostream>
#include <memory> // 包含 shared_ptr 和 make_shared
class MySharedResource {
public:
MySharedResource() { std::cout << "MySharedResource created\n"; }
~MySharedResource() { std::cout << "MySharedResource destroyed\n"; }
void report() { std::cout << "Shared resource is active.\n"; }
};
int main() {
std::shared_ptr<MySharedResource> s_ptr1 = std::make_shared<MySharedResource>();
std::cout << "s_ptr1 ref count: " << s_ptr1.use_count() << std::endl; // 1
{
std::shared_ptr<MySharedResource> s_ptr2 = s_ptr1; // 拷贝,引用计数增加
std::cout << "s_ptr1 ref count: " << s_ptr1.use_count() << std::endl; // 2
s_ptr2->report();
} // s_ptr2离开作用域,引用计数减1
std::cout << "s_ptr1 ref count: " << s_ptr1.use_count() << std::endl; // 1
s_ptr1->report();
// s_ptr1离开作用域,引用计数减到0,MySharedResource被销毁
return 0;
}选择哪个,取决于你对内存所有权的设计。如果你能明确谁是唯一的拥有者,
unique_ptr
shared_ptr
weak_ptr
shared_ptr
std::weak_ptr
unique_ptr
shared_ptr
shared_ptr
循环引用问题
shared_ptr
shared_ptr
考虑一个简单的父子关系:一个
Parent
shared_ptr
Child
Child
shared_ptr
Parent
#include <iostream>
#include <memory>
class Child; // 前向声明
class Parent {
public:
std::shared_ptr<Child> child_ptr;
Parent() { std::cout << "Parent created\n"; }
~Parent() { std::cout << "Parent destroyed\n"; }
};
class Child {
public:
std::shared_ptr<Parent> parent_ptr; // 这里是问题所在
Child() { std::cout << "Child created\n"; }
~Child() { std::cout << "Child destroyed\n"; }
};
int main() {
{
std::shared_ptr<Parent> p = std::make_shared<Parent>();
std::shared_ptr<Child> c = std::make_shared<Child>();
p->child_ptr = c;
c->parent_ptr = p;
std::cout << "Parent ref count: " << p.use_count() << std::endl; // 2 (p自身 + c->parent_ptr)
std::cout << "Child ref count: " << c.use_count() << std::endl; // 2 (c自身 + p->child_ptr)
} // p和c离开作用域,但Parent和Child的析构函数都没有被调用!
std::cout << "Exiting scope. Objects should have been destroyed, but might not be due to circular reference.\n";
return 0;
}在这个例子中,当
p
c
p
c->parent_ptr
c
p->child_ptr
Parent
Child
weak_ptr
weak_ptr
weak_ptr
weak_ptr
shared_ptr
要访问
weak_ptr
lock()
shared_ptr
shared_ptr
lock()
shared_ptr
shared_ptr
修正上述循环引用问题的方法是,让其中一个指针变成
weak_ptr
weak_ptr
#include <iostream>
#include <memory>
class ChildFixed; // 前向声明
class ParentFixed {
public:
std::shared_ptr<ChildFixed> child_ptr;
ParentFixed() { std::cout << "ParentFixed created\n"; }
~ParentFixed() { std::cout << "ParentFixed destroyed\n"; }
};
class ChildFixed {
public:
std::weak_ptr<ParentFixed> parent_ptr; // 使用 weak_ptr
ChildFixed() { std::cout << "ChildFixed created\n"; }
~ChildFixed() { std::cout << "ChildFixed destroyed\n"; }
void accessParent() {
if (auto p = parent_ptr.lock()) { // 尝试获取 shared_ptr
std::cout << "ChildFixed can access ParentFixed.\n";
} else {
std::cout << "ParentFixed no longer exists.\n";
}
}
};
int main() {
{
std::shared_ptr<ParentFixed> p = std::make_shared<ParentFixed>();
std::shared_ptr<ChildFixed> c = std::make_shared<ChildFixed>();
p->child_ptr = c;
c->parent_ptr = p; // weak_ptr 不增加引用计数
std::cout << "ParentFixed ref count: " << p.use_count() << std::endl; // 2 (p自身 + p->child_ptr)
std::cout << "ChildFixed ref count: " << c.use_count() << std::endl; // 2 (c自身 + c->parent_ptr指向的Parent的引用计数是1)
// 注意:c->parent_ptr是weak_ptr,它不影响p的引用计数。p的引用计数是2是因为p自身和p->child_ptr指向的c的parent_ptr(如果它也是shared_ptr)
// 这里需要更正,p的引用计数是2是因为p自身和c->parent_ptr指向的p。
// 而c的引用计数是2是因为c自身和p->child_ptr指向的c。
// 在ChildFixed中,parent_ptr是weak_ptr,所以它不会增加ParentFixed的引用计数。
// 实际上,p的引用计数是1(只有p自身),c的引用计数是2(c自身 + p->child_ptr)。
// 让我们重新检查这个逻辑。
// p的引用计数:
// 1. p = make_shared<ParentFixed>() -> p的引用计数为1
// 2. p->child_ptr = c -> c的引用计数为2 (c自身 + p->child_ptr)
// 3. c->parent_ptr = p -> p的引用计数仍为1,因为c->parent_ptr是weak_ptr
// 实际输出应该是:
// ParentFixed ref count: 1
// ChildFixed ref count: 2
std::cout << "ParentFixed ref count: " << p.use_count() << std::endl; // 1
std::cout << "ChildFixed ref count: " << c.use_count() << std::endl; // 2
c->accessParent(); // 可以访问
} // p和c离开作用域。
// 首先,c的引用计数降为1(p->child_ptr还指向它)。
// 然后,p的引用计数降为0,ParentFixed被销毁。
// ParentFixed销毁后,p->child_ptr不再指向c,c的引用计数降为0,ChildFixed被销毁。
std::cout << "Exiting scope. Objects should now be destroyed.\n";
return 0;
}通过使用
weak_ptr
weak_ptr
以上就是C++内存回收策略 智能指针生命周期的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号