使用智能指针作为类成员可实现自动内存管理,避免内存泄漏和悬空指针。通过RAII原则,智能指针在对象构造时获取资源,在析构时自动释放,无需手动delete。std::unique_ptr适用于独占所有权场景,开销小且安全;std::shared_ptr用于共享所有权,但需警惕循环引用问题,可用std::weak_ptr打破循环。推荐在构造函数初始化列表中使用std::make_unique和std::make_shared进行初始化,以保证异常安全和性能优化。避免将原始指针与智能指针混用,防止双重释放。智能指针的选择应遵循“优先unique_ptr,必要时再用shared_ptr”的原则,同时注意传递方式:const shared_ptr<T>&用于观察,值传递用于共享,unique_ptr<T>&&用于转移所有权。正确使用智能指针能显著提升代码安全性与可维护性。

在C++中,将智能指针作为类成员是一种非常推荐的做法,它能有效解决传统原始指针带来的内存管理难题,例如内存泄漏、悬空指针等。通过这种方式,我们可以利用RAII(Resource Acquisition Is Initialization)原则,让资源的生命周期与对象的生命周期绑定,从而实现自动化的内存管理,极大地简化了代码并提高了程序的健壮性。
将智能指针(如
std::unique_ptr
std::shared_ptr
delete
举个例子,假设我们有一个
Resource
MyClass
Resource
#include <iostream>
#include <memory> // 包含智能指针头文件
// 假设有一个资源类
class Resource {
public:
int value;
Resource(int v) : value(v) {
std::cout << "Resource " << value << " created." << std::endl;
}
~Resource() {
std::cout << "Resource " << value << " destroyed." << std::endl;
}
void doSomething() {
std::cout << "Resource " << value << " is doing something." << std::endl;
}
};
class MyClass {
public:
// 使用 std::unique_ptr 作为成员变量,表示独占所有权
std::unique_ptr<Resource> uniqueRes;
// 使用 std::shared_ptr 作为成员变量,表示共享所有权
std::shared_ptr<Resource> sharedRes;
// 构造函数中初始化智能指针
// 推荐使用 std::make_unique 和 std::make_shared
MyClass(int uniqueVal, int sharedVal)
: uniqueRes(std::make_unique<Resource>(uniqueVal)),
sharedRes(std::make_shared<Resource>(sharedVal)) {
std::cout << "MyClass object created." << std::endl;
}
// 也可以在运行时赋值或重新分配
void replaceUniqueResource(int newVal) {
uniqueRes = std::make_unique<Resource>(newVal); // 旧的uniqueRes会自动销毁
}
void showResources() {
if (uniqueRes) {
uniqueRes->doSomething();
}
if (sharedRes) {
sharedRes->doSomething();
}
}
~MyClass() {
std::cout << "MyClass object destroyed." << std::endl;
}
};
int main() {
{ // 局部作用域,MyClass对象在此处创建和销毁
MyClass obj(10, 20);
obj.showResources();
obj.replaceUniqueResource(30); // 替换uniqueRes,旧的10会被销毁
obj.showResources();
// 也可以创建另一个共享指针来引用同一个资源
std::shared_ptr<Resource> anotherShared = obj.sharedRes;
std::cout << "Shared resource use count: " << obj.sharedRes.use_count() << std::endl;
} // obj在这里销毁,uniqueRes和sharedRes也会自动销毁其管理的资源
std::cout << "End of main." << std::endl;
return 0;
}这段代码清晰地展示了智能指针作为类成员的用法。
MyClass
Resource
uniqueRes
sharedRes
MyClass
obj
uniqueRes
sharedRes
Resource
立即学习“C++免费学习笔记(深入)”;
说实话,我个人觉得,在C++里处理资源(特别是堆内存)的生命周期,一直是个挺让人头疼的问题。你得记得
new
delete
智能指针的出现,在我看来,就是为了解决这些“人祸”。当我们将智能指针作为类成员时,它的优势简直是压倒性的:
new
delete
std::unique_ptr
unique_ptr
std::shared_ptr
shared_ptr
shared_ptr
unique_ptr
shared_ptr
delete
delete
shared_ptr
unique_ptr
总的来说,使用智能指针作为类成员,不仅让我们的代码更安全、更易维护,也让开发者能更专注于业务逻辑,而不是疲于应对底层内存管理的细节。
std::unique_ptr
std::shared_ptr
这确实是很多初学者会纠结的问题,毕竟这俩哥们儿看着都能管内存,但骨子里差别挺大。选择哪个,很大程度上取决于你的类对它所管理的资源是“独占”还是“共享”的关系。
选择策略:
std::unique_ptr
unique_ptr
Car
Engine
Engine
Car
unique_ptr
unique_ptr
unique_ptr
unique_ptr
shared_ptr
std::shared_ptr
shared_ptr
User
DatabaseConnection
shared_ptr
shared_ptr
unique_ptr
初始化方法:
无论选择哪种智能指针,初始化都应该尽可能在成员初始化列表中完成,并强烈推荐使用
std::make_unique
std::make_shared
使用 std::unique_ptr
class MyClassWithUnique {
private:
std::unique_ptr<Resource> myResource;
public:
// 推荐:使用 std::make_unique 在初始化列表中创建对象
MyClassWithUnique(int val) : myResource(std::make_unique<Resource>(val)) {
// ...
}
// 如果资源可能为空,或者在构造后才决定创建
MyClassWithUnique() : myResource(nullptr) { // 显式初始化为nullptr
// 之后再创建
// myResource = std::make_unique<Resource>(some_value);
}
// 接受一个已存在的 unique_ptr (所有权转移)
MyClassWithUnique(std::unique_ptr<Resource> res) : myResource(std::move(res)) {
// ...
}
};std::make_unique
Resource
unique_ptr
使用 std::shared_ptr
class MyClassWithShared {
private:
std::shared_ptr<Resource> mySharedResource;
public:
// 推荐:使用 std::make_shared 在初始化列表中创建对象
MyClassWithShared(int val) : mySharedResource(std::make_shared<Resource>(val)) {
// ...
}
// 接受一个已存在的 shared_ptr (共享所有权)
MyClassWithShared(std::shared_ptr<Resource> res) : mySharedResource(res) {
// ...
}
// 如果资源可能为空,或者在构造后才决定创建
MyClassWithShared() : mySharedResource(nullptr) { // 显式初始化为nullptr
// 之后再创建
// mySharedResource = std::make_shared<Resource>(some_value);
}
};std::make_shared
std::make_unique
在选择和初始化时,核心原则是:先考虑独占,再考虑共享;优先使用
make_unique
make_shared
虽然智能指针极大地简化了内存管理,但它也不是万能药,使用不当同样会引入问题。这里我总结了一些常见的陷阱和一些我个人觉得很实用的最佳实践。
常见陷阱:
std::shared_ptr
shared_ptr
shared_ptr
class B; // 前向声明
class A {
public:
std::shared_ptr<B> b_ptr;
~A() { std::cout << "A destroyed." << std::endl; }
};
class B {
public:
std::shared_ptr<A> a_ptr;
~B() { std::cout << "B destroyed." << std::endl; }
};
// 在某个函数中创建循环引用
// std::shared_ptr<A> pa = std::make_shared<A>();
// std::shared_ptr<B> pb = std::make_shared<B>();
// pa->b_ptr = pb;
// pb->a_ptr = pa;
// 此时 pa 和 pb 的引用计数都为 2,它们永远不会被销毁解决方案:使用
std::weak_ptr
weak_ptr
shared_ptr
shared_ptr
class B;
class A {
public:
std::shared_ptr<B> b_ptr;
~A() { std::cout << "A destroyed." << std::endl; }
};
class B {
public:
std::weak_ptr<A> a_ptr; // 使用 weak_ptr
~B() { std::cout << "B destroyed." << std::endl; }
};
// 这样,当 pa 和 pb 离开作用域时,它们的引用计数会降到 0,资源就能正常释放了。智能指针与原始指针的混用:当你从智能指针中取出原始指针(例如通过
get()
delete
std::unique_ptr
std::shared_ptr
delete
get()
delete
delete
不正确的std::shared_ptr
shared_ptr
Resource* res = new Resource(100); std::shared_ptr<Resource> s_ptr1(res); std::shared_ptr<Resource> s_ptr2(res); // 错误!双重释放
最佳实践:始终使用
std::make_shared
shared_ptr
shared_ptr
shared_ptr
shared_ptr
最佳实践:
std::unique_ptr
unique_ptr
std::move
shared_ptr
std::make_unique
std::make_shared
new T()
std::shared_ptr<T>(...)
const std::shared_ptr<T>&
std::shared_ptr<T>
std::unique_ptr<T>
std::unique_ptr<T>&&
std::move
unique_ptr
get()
get()
unique_ptr
shared_ptr
通过遵循这些实践并警惕常见陷阱,智能指针将成为你C++编程中一个极其强大且可靠的伙伴,让你的代码更加健壮和易于维护。
以上就是C++智能指针在类成员中使用方法的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号