💨一:说在前头(前言)🌈
为了更容易(同时也更安全)地使用动态内存,C++标准库提供了两种智能指针类型来管理创建的动态内存。shared_ptr类型允许多个指针同时指向一个对象,unique_ptr则“独占”对象,unique_ptr所指向的对象再其生命周期内只能被一个unique_ptr所拥有。此外,标准库还提供了一种智能指针类型weak_ptr,它与shared_ptr紧密配合,主要起到辅助和监测的作用。还有一种在C++17的标准中被彻底废弃的智能指针类型auto_ptr,现在已被unique_ptr所替代,在这里不做赘述。
实际上智能指针与普通指针没有什么太大的区别,唯一的区别就是智能指针可以自动释放我们自己动态分配的内存空间,这一特性极大的提高了代码的安全性,也便利了代码的后续维护,最主要的时令操作人员不那么头大!🤔💦💦💦
⛔以下声明均在使用了命名空间下使用的
using namespace std;
💨二:auto_ptr智能指针类型🌈
1.简介
auto_ptr
是 C++98 标准库中的一个智能指针类型,它用于自动管理动态分配的内存。从 C++11 开始,auto_ptr
已被弃用,并在 C++17 中被彻底移除。这是因为 auto_ptr
的所有权转移语义(当它被拷贝时,所有权会转移给新的拷贝,原对象将不再拥有指针)经常导致难以察觉的错误。因此,现代 C++ 代码通常推荐使用 unique_ptr
、shared_ptr
和 weak_ptr
这些更安全的智能指针。
2.弊端🔥
(1) 所有权转移语义
auto_ptr对象被拷贝时,所有权(即管理底层指针的责任)会转移给新的对象。原始auto_ptr在拷贝操作后会变为空指针。它实际上导致了复杂的所有权问题,使得代码难以理解和维护。
(2)潜在的内存问题
由于所有权转移的特性,auto_ptr容易导致内存问题。当多个auto_ptr对象指向同一块内存时,每个对象都认为自己是该内存块的唯一所有者。当其中一个auto_ptr对象被销毁时,它可能会删除同一块内存,导致其他auto_ptr对象变成悬垂指针,进而引发未定义行为。
(3)不支持数组
auto_ptr的析构函数使用delete而不是delete[]来释放内存。这意味着它不能安全地管理动态分配的数组。如果使用auto_ptr来管理数组,将会导致内存泄漏或其他未定义行为。
(4) 不符合现代C++的核心理念
现代C++强调资源的安全管理和清晰的所有权模型。auto_ptr的所有权转移语义违反了这些原则,使得代码更难以理解和维护。相比之下,unique_ptr和shared_ptr等智能指针提供了更清晰、更安全的所有权语义,更符合现代C++的编程实践。
(5)已被弃用和移除
由于上述弊端,auto_ptr在C++11中已被弃用,并在C++17中被彻底移除。
💨三:unique_ptr智能指针类型🌈
1.简介
unique_ptr是C++11中引入的一种智能指针,用于管理动态分配的对象。它实现了独享被管理对象指针的概念,确保一个对象和其对应的资源在同一时间只被一个unique_ptr对象拥有。在C++14又为其添加了与C++11中make_shared有同样作用的make_unique,可以更安全便捷的使用。
2.unique_ptr相关特性
(1)独占所有权
unique_ptr具有独占所有权的特性,意味着两个unique_ptr不能指向同一个对象。一旦一个unique_ptr指向了某个对象,其他的unique_ptr就不能再指向该对象。
unique_ptr<int> p1 = make_unique<int>(100);
unique_ptr<int> p2 = p1; //错误,此时p2和p1都指向了同一个对象
(2)不可复制性
unique_ptr对象不能进行复制操作,只能进行移动操作。这是为了确保对象的独占性。尝试复制一个unique_ptr会导致编译错误。
unique_ptr<int> p1 = make_unique<int>(100);
unique_ptr<int> p2 = move(p1); //它表示我们想要将p1的所有权转移到另一个unique_ptr
//p1现在不再拥有对原来int对象的所有权
//这意味着p1现在是一个空指针(即它不指向任何对象)
//而p2现在拥有对原来int对象的所有权,当p2的生命周期结束时,该对象将被删除。
(3)自动释放资源
当unique_ptr对象本身被删除或离开其作用域时,它会自动释放其所指向对象所占用的资源。这有助于避免内存泄漏和其他资源管理问题。
{ //新的作用域块
unique_ptr<int> p1 = make_unique<int>(100);
unique_ptr<int> p2 = move(p1); //p1所有权被转移,会自动释放它所管理的资源
}
//离开作用域后,p2也会自动释放它所管理的资源
//此时p1,p2均是空指针
(4)创建与初始化
可以使用make_unique</*数据类型*/>()函数来创建并初始化一个unique_ptr。
// 错误用法:不应该用 new 与 unique_ptr 直接结合
unique_ptr<int> p1 = new int(); // 错误
// 正确用法:使用 make_unique 创建 unique_ptr
unique_ptr<int> p1 = make_unique<int>(); // 默认初始化 int
// 正确用法:使用 make_unique 创建 unique_ptr 并初始化 int 为 100
unique_ptr<int> p2 = make_unique<int>(100);
// 正确用法:使用 make_unique 创建 unique_ptr 并初始化 int 为 1
unique_ptr<int> p3 = make_unique<int>(1);
// 错误用法:不应直接使用 new 创建 unique_ptr
unique_ptr<int> p4(new int(2)); // 错误,不推荐
// 如果确实需要,可以这样显式使用 unique_ptr 的构造函数
// 但请注意,这通常是不必要的,因为 make_unique 更为简洁和安全
unique_ptr<int> p4(new int(2)); // 可以工作,但不推荐
// 推荐做法:始终使用 make_unique
unique_ptr<int> p5 = make_unique<int>(2); // 正确用法
unique_ptr不应该与new一起使用,因为unique_ptr负责管理对象的生命周期,包括删除对象。如果您使用new来创建对象,并将其赋给unique_ptr,那么unique_ptr将无法知道它应该何时删除这个对象,因为它没有参与对象的创建过程。正确的方法是使用make_unique来创建unique_ptr,因为它会同时分配内存并返回指向新分配对象的unique_ptr。
(5)访问资源
可以使用箭头操作符(->)或解引用操作符(*)来访问unique_ptr所管理的资源。例如,如果ptr是一个指向整数的unique_ptr,那么*ptr就可以用来获取或设置整数的值。
下面代码仅为测试使用,没有进行构造函数的设置。
#include<iostream>
#include<memory>
using namespace std;
class Test {
public:
void setValue(int new_value) { value = new_value; } //设置函数
int getValue() const {return value;} //获取函数
private:
int value;
};
int main()
{
unique_ptr<Test> pt = make_unique<Test>(); //将指针指向我所创建的Test类
pt->setValue(100); //利用箭头运算符访问类内设置函数并将value设为100
cout << (*pt).getValue() << endl; //利用解引用运算符得到指针所指的对象,并用.运算符得到值
return 0;
}
(6)所有权转移
虽然unique_ptr不能进行复制操作,但可以通过std::move()函数来转移其所有权。这意味着可以将一个unique_ptr的所有权转移给另一个unique_ptr,使得原本拥有所有权的unique_ptr不再指向任何对象。
使用release()进行转移 ❌❌❌不推荐
#include <iostream>
#include <memory>
using namespace std;
int main() {
// 创建一个指向int的unique_ptr
unique_ptr<int> ptr1(new int(42));
// 输出ptr1所指向的值
cout << "ptr1 points to: " << *ptr1 << endl;
// 创建一个空的unique_ptr
unique_ptr<int> ptr2;
// 使用move将ptr1的所有权转移给ptr2
ptr2 = move(ptr1);
// 输出ptr2所指向的值,它现在拥有原来的值
cout << "ptr2 = " << *ptr2 << endl;
// 尝试访问ptr1指向的值将导致未定义行为,因为ptr1现在为空
cout << "ptr1 = " << *ptr1 << endl; // 错误的操作,不要这样做
// 检查ptr1是否为空
if (!ptr1)
{
cout << "ptr1 is now null." << endl;
}
// ptr2将在离开作用域时自动删除其指向的int
return 0;
}
使用 release() 时需要非常小心,因为一旦释放了所有权,你就必须确保正确地管理原始指针的生命周期。如果你忘记了删除原始指针,或者试图在删除后再次访问它,都会导致未定义行为,包括可能的内存泄漏或程序崩溃。
通常情况下,更推荐使用智能指针(如 unique_ptr 或 shared_ptr)来自动管理资源,而不是手动使用 new 和 delete。如果你确实需要释放 unique_ptr 的所有权,并且确信能够妥善地管理返回的原始指针,那么 release() 可以是一个选项。然而,在大多数情况下,更好的做法是通过移动语义来转移所有权,而不是使用 release()。
使用move()进行转移 ✅✅✅推荐做法
#include<iostream>
#include<memory>
using namespace std;
int main()
{
// 创建一个指向int的unique_ptr
unique_ptr<int> p1(new int(2002));
// 输出p1所指向的值
cout << "p1 = " << *p1 << endl;
// 创建一个空的unique_ptr
unique_ptr<int> p2;
// 使用将p1的所有权转移给ptr2
ptr2 = move(ptr1);
// 输出p2所指向的值,它现在拥有原来的值
cout << "p2 = " << *p2 << endl;
// 尝试访问ptr1指向的值将导致未定义行为,因为ptr1现在为空
cout << "p1 = " << *p1 << endl; // 错误的操作,不要这样做
// 检查ptr1是否为空
if (!ptr1)
{
cout << "p1 now is null." << endl;
}
// p2将在离开作用域时自动删除其指向的int
return 0;
}
在转移所有权后,试图访问 p1
所指向的对象是不安全的,因为它现在是一个空指针。在编程实践中,应当总是检查 unique_ptr
是否为空,以避免未定义行为。
move()的这一过程实际上并不涉及数据的移动或拷贝,而是允许在函数中使用移动语义,从而避免不必要的拷贝操作,提高程序的性能。
💨四:shared_ptr智能指针类型🌈
1.简介
shared_ptr
是C++标准库中的一个智能指针类型,主要用于动态内存管理。shared_ptr类型允许多个指针同时指向一个对象,它通过引用计数来记录指向某个动态分配对象的指针数量,以便自动地、安全地管理内存。当shared_ptr
的引用计数减少到0时,它会自动删除所管理的对象,并释放相关的内存资源,从而避免了内存泄漏等问题。
2.声明方法
2.1 正确的声明方法
(1)使用 make_shared
make_shared
是一个方便且高效的函数,用于创建一个 shared_ptr
并同时分配内存。它接受类型和一个或多个参数,用于构造对象。
shared_ptr<int> p1 = make_shared<int>(42); // 创建一个值为 42 的 int 的 shared_ptr
对于数组,make_shared
同样适用,但你需要使用 shared_ptr
的数组特化版本:
shared_ptr<int[]> arr = make_shared<int[]>(5); // 创建一个包含 5 个 int 的数组
for (int i = 0; i < 5; ++i)
{
arr[i] = i;
}
(2)使用 shared_ptr
构造函数:
虽然直接使用 shared_ptr
的构造函数不如 make_shared
常用,但在某些情况下可能是必要的。你可以将一个裸指针传递给 shared_ptr
的构造函数,但请注意,这样做不会删除原有的裸指针(如果它之前是由 new
分配的),可能会导致内存泄漏。因此,通常只有在从某个函数接收裸指针并希望接管其所有权时才这样做。
int* ptr = new int(42);
shared_ptr<int> p2(ptr); // 接管ptr的所有权
// 此时,不应再使用ptr,因为它现在由shared_ptr管理
(3)局部变量的自动推断:
当使用 auto
关键字时,make_shared
返回的类型会被自动推断为正确的 shared_ptr
类型。
auto p3 = make_shared<int>(100); // 推断出 p3 是 shared_ptr<int> 类型
2.2 错误的声明方法🔥🔥🔥
(1)尝试直接将原始指针赋值给 shared_ptr
:
int* ptr = new int(5);
shared_ptr<int> sp = ptr; // 错误!这不会接管原始指针的所有权
上面的代码是错误的,因为 shared_ptr
没有从原始指针接管所有权的赋值运算符。原始指针 ptr
仍然指向该内存,而 shared_ptr
并没有管理这块内存,这可能导致双重释放或其他内存问题。
(2)使用错误的类型参数:
shared_ptr<int[]> p(new int(5)); // 错误!应该使用 shared_ptr<int[]> 来管理数组
如果你想管理一个动态分配的数组,你应该使用 shared_ptr<int[]>
而不是 shared_ptr<int>
。
(3)使用函数声明语法时错误地传递原始指针
shared_ptr<int> sp(new int(5)); // 正确
shared_ptr<int> sp2(ptr); // 错误!这不会接管原始指针的所有权
使用函数声明语法初始化 shared_ptr
时,你应该传递一个 new
表达式的结果,而不是一个已经存在的原始指针。
(4)错误地假设 shared_ptr
可以隐式转换为原始指针:
shared_ptr<int> sp(new int(5));
int* ptr = sp; // 错误!不能隐式转换
你不能直接将 shared_ptr
隐式转换为原始指针。你需要使用 get()
成员函数来获取原始指针:
int* ptr = sp.get();
(5)使用 auto
关键字时未正确推断类型:
auto sp = new int(5); // 错误!这将推断出 int* 类型,而不是 shared_ptr<int>
使用 auto
关键字时,编译器会根据初始化表达式的类型来推断变量的类型。在上面的例子中,auto
将推断出 int*
类型,而不是 shared_ptr<int>
。你应该显式地指定 shared_ptr
类型:
auto sp = make_shared<int>(5); // 正确,推断出 shared_ptr<int> 类型
(6)错误地初始化 shared_ptr
数组:
shared_ptr<int[]> arr(new int[5]{1, 2, 3, 4, 5}); // 错误!这不会正确管理数组
虽然上面的代码在语法上可能看起来是正确的,但使用 new[]
和 shared_ptr</*数据类型*/>
的组合并不是最佳实践。你应该使用 make_shared
或 shared_ptr
的数组特化版本来管理动态分配的数组:
shared_ptr<int[]> arr = make_shared<int[]>(5); // 正确,但未初始化数组元素
// 或者手动初始化每个元素
for (int i = 0; i != 5; ++i)
{
arr[i] = i + 1;
}
避免上述错误的关键是确保正确使用 'shared_ptr',始终使用 'make_shared' 来初始化它(如果可能),并且不要混用原始指针和智能指针,除非在必要的情况下(比如为了兼容一些古老的代码)。
3.引用计数的简介
当你使用make_shared<int>()
来创建一个shared_ptr<int>
时,此时该引用计数为1,每当有另一个shared_ptr
通过拷贝构造、移动构造或赋值操作来共享同一个对象时,引用计数就会增加。同样地,每当一个shared_ptr
被销毁(例如超出其作用域或被重新赋值)时,引用计数就会减少。当引用计数减少到0时,控制块会负责删除整数对象,并释放其占用的内存。这就是shared_ptr
如何确保自动内存管理的。
引用计数具体的变化详情
auto r = make_shared<int>(1); //r指向的int只有一个引用者
auto q = make_shared<int>(2); //q指向的int也只有一个引用者
r = q; //给r赋值,令它指向另一个地址
//递增q指向的对象的引用计数
//递减r原来指向的对象的引用计数
//r原来指向的对象已没有引用者,会自动释放
//综合来看,使用拷贝时,会递增=右侧的引用计数,递减=左侧的引用计数
因为在将r指向另一个地址后,r最开始指向的地址就没有指针指着了,该空间则会被自动释放,如果使用普通指针,则该空间需要手动释放。
shared_ptr<int> p1 = make_shared<int> ();//引用计数为1,因为此时该对象只被shared_ptr对象指着
shared_ptr<int> p2 = p1;//引用计数为2,此时p2和p1都指向同一个对象
shared_ptr<int> p3 = p2;//引用计数为3,此时P3,P2,P1都指向同一个对象
每个shared_ptr对象都指向同一个动态分配的int对象,并且它们的引用计数是共享的。
shared_ptr<int> p1 = make_shared<int> (); //这行代码创建了一个shared_ptr<int>对象p1,它指向
//一个新分配的int对象。此时,引用计数为1(因为只有
//p1指向这个对象)
shared_ptr<int> p2 = p1; //这行代码通过拷贝构造创建了一个新的shared_ptr<int>对象p2,它指向
//与p1相同的int对象。这个操作会增加引用计数,因为现在有两个
//shared_ptr对象指向同一个对象。因此,引用计数增加到2。
shared_ptr<int> p3 = p2; //同样地,这行代码又通过拷贝构造创建了一个新的shared_ptr<int>对象
//p3,它也指向与p1和p2相同的int对象。这个操作再次增加引用计数,因为
//现在有三个shared_ptr对象指向同一个对象。因此,引用计数增加到3。
💨五.weak_ptr智能指针类型🌈
1.简介
weak_ptr是C++标准库中的一个智能指针类型,它是为了配合shared_ptr而设计的,主要用于解决shared_ptr在某些情况下(如循环引用)可能导致的内存泄漏问题。weak_ptr是一种不控制对象生命周期的智能指针,它指向一个由shared_ptr管理的对象,但不会增加对象的引用计数。当需要访问该对象时,可以通过weak_ptr的lock()函数临时获取一个shared_ptr,以确保在访问期间对象不会被删除。
2.weak_ptr的相关特性
(1)构造和析构
weak_ptr
的构造和析构不会改变对象的引用计数,这是weak_ptr
和shared_ptr
之间的重要区别之一。weak_ptr
主要用于观察shared_ptr
所管理的对象,但不参与对象的生命周期管理。
#include <iostream>
#include <memory>
using namespace std;
class MyClass {
public:
MyClass(int value) : value1(value) {
cout << "MyClass(" << value1 << ") constructed << endl;
}
~MyClass() {
cout << "MyClass(" << value1 << ") destroyed << endl;
}
void printValue() const {
cout << "Value: " << value1 << endl;
}
private:
int value1;
};
int main()
{
// 创建一个shared_ptr来管理一个MyClass实例
shared_ptr<MyClass> sptr = std::make_shared<MyClass>(42);
// 使用shared_ptr构造一个weak_ptr
weak_ptr<MyClass> wptr = sptr;
// 此时不会改变MyClass实例的引用计数
// 因为weak_ptr只是观察对象,不参与引用计数
// 打印引用计数(需要访问shared_ptr的内部状态,这通常是不推荐的,这里仅为示例)
cout << "Shared pointer use count: " << sptr.use_count() << endl;
// 使用weak_ptr不会增加引用计数
// 当weak_ptr构造或析构时,对象的生命周期不会受到影响
{
weak_ptr<MyClass> anotherWptr = wptr;
// 在这个作用域内,anotherWptr存在,但不会影响引用计数
}
// 再次打印引用计数,应该和之前一样
cout << "Shared pointer use count after another weak_ptr destruction: " << sptr.use_count() << endl;
// 当最后一个shared_ptr被销毁时,对象才会被删除
sptr.reset();
// 尝试使用weak_ptr访问对象会导致异常或未定义行为
// 因为此时对象已经被删除了
// shared_ptr<MyClass> strongFromWeak = wptr.lock();
// if (strongFromWeak)
// {
// strongFromWeak->printValue();
// }
return 0;
}
(2)lock()函数
weak_ptr
的 lock()
函数用于尝试从 weak_ptr
创建一个 shared_ptr
。如果 weak_ptr
当前观察的对象仍然存在(即它没有被 shared_ptr
删除),lock()
函数将返回一个新的 shared_ptr
,它指向同一个对象,并增加该对象的引用计数。如果对象已经被删除,lock()
函数将返回一个空的 shared_ptr
。
#include <memory>
#include <iostream>
using namespace std;
int main()
{
shared_ptr<int> sp = make_shared<int>(42);
//用这个 shared_ptr 初始化了一个 weak_ptr
weak_ptr<int> wp = sp;
//使用 lock() 函数从 weak_ptr 创建一个新的 shared_ptr。
shared_ptr<int> sp2 = wp.lock();
if (sp2)
{
cout << "Object still exists, value is " << *sp2 << endl;
}
else
{
cout << "Object no longer exists" << endl;
}
return 0;
}
(3)expired()函数
weak_ptr
的 expired()
函数用于检测它所观察的对象是否已经被 shared_ptr
删除。如果对象已经被删除,expired()
将返回 true
;否则,返回 false
。它允许你在尝试从 weak_ptr
创建一个 shared_ptr
之前,先检查对象是否还存在。这可以避免不必要的 lock()
调用,以及在对象已经被删除的情况下尝试访问它可能导致的未定义行为。
#include <memory>
#include <iostream>
using namespace std;
int main() {
shared_ptr<int> sp = make_shared<int>(42);
//用shared_ptr初始化了一个 weak_ptr
weak_ptr<int> wp = sp;
//如果 expired() 返回 true,我们打印出对象已经过期,不能安全访问的消息。
//如果返回 false,我们使用 lock() 创建一个新的 shared_ptr 并访问对象的值。
if (wp.expired())
{
cout << "Object has expired, cannot be accessed safely." << endl;
}
else
{
shared_ptr<int> sp2 = wp.lock();
cout << "Object still exists, value is " << *sp2 << endl;
}
return 0;
}
(4)use_count()函数
use_count()
函数是 shared_ptr
的一个成员函数,它返回当前与 shared_ptr
共享对象的 shared_ptr
(包括它自己)的数量。尽管 weak_ptr
不控制对象的生命周期,也不直接参与引用计数,但 use_count()
函数可以帮助你了解与 weak_ptr
所观察的对象相关联的 shared_ptr
的数量。
#include <memory>
#include <iostream>
using namespace std;
int main()
{
shared_ptr<int> sp1 = std::make_shared<int>(42);
cout << "Initial use count: " << sp1.use_count() << endl; // 输出 1
{
shared_ptr<int> sp2 = sp1;
cout << "After copying sp1 to sp2: " << sp1.use_count() << endl; // 输出 2
weak_ptr<int> wp = sp1;
cout << "After creating wp from sp1: " << sp1.use_count() << endl; // 仍然输出 2,因为 weak_ptr 不影响引用计数
}
cout << "After sp2 goes out of scope: " << sp1.use_count() << endl; // 输出 1
return 0;
}
总的来说,weak_ptr智能指针类型在C++编程中主要用于解决由shared_ptr引起的循环引用问题,以及提高代码的安全性和可维护性。通过合理地使用weak_ptr和shared_ptr,开发者可以更加有效地管理动态分配的内存资源,并减少内存泄漏和程序崩溃等问题的发生。
💨六.对于智能指针的选择🌈
智能指针在C++中提供了一种自动管理动态分配内存的机制,避免了手动管理内存时可能出现的内存泄漏和悬挂指针等问题。选择使用哪种智能指针主要取决于你的具体需求以及对象的生命周期管理要求。
1.unique_ptr
使用场景:当你需要一个独占所有权的智能指针时,即同一时间内只能有一个智能指针指向某个对象。
特点:不可复制,但可移动(通过move)。当unique_ptr被销毁时,它所指向的对象也会被删除。
2.shared_ptr
使用场景:当你需要共享所有权时,即多个智能指针可以指向同一个对象,并且当最后一个指向该对象的智能指针被销毁时,对象才会被删除。这在多个组件需要访问同一资源时非常有用。
特点:内部使用引用计数来跟踪有多少个shared_ptr指向同一个对象。当引用计数降为0时,对象会被删除。
3.weak_ptr
使用场景:当你需要观察shared_ptr所管理的对象,但不参与其生命周期管理时。weak_ptr不控制对象的生命周期,它不会增加对象的引用计数。
特点:主要用于避免循环引用导致的内存泄漏。当你想从一个shared_ptr网络中的某个点“跳出”并观察对象,但不想延长其生命周期时,weak_ptr非常有用。
4.原始指针
使用场景:在某些情况下,使用原始指针仍然是必要的,特别是在与C语言库交互或某些特定性能敏感的场景中。应尽可能避免在C++代码中使用原始指针来管理动态内存,以减少内存泄漏和悬挂指针的风险。
⚡⚡⚡选择建议:
1.如果你需要独占所有权并且不希望复制指针,使用unique_ptr。
2.如果你需要共享所有权并且希望自动管理对象的生命周期,使用shared_ptr。
3.如果你只想观察shared_ptr管理的对象而不参与其生命周期管理,或者需要解决循环引用问题,4.使用weak_ptr。
5.尽量避免使用原始指针来管理动态内存,除非有特别的原因(如与C库交互)。
❗❗❗注意事项:
1.使用智能指针时,要注意避免野指针问题,即智能指针已经释放了它所指向的对象,但代码中仍保留了对该对象的引用。
2.当使用shared_ptr时,要特别注意循环引用问题,因为这可能导致内存泄漏。可以通过使用weak_ptr来打破循环引用。
3.在某些情况下,可能需要自定义删除器或分配器来与智能指针一起使用,以满足特定的内存管理需求。
最后再进行强调,在C++中,智能指针相较于普通指针一定是更优的选择,能使用智能指针的地方就不要使用普通指针。学会灵活且熟练的使用智能指针一定会减少你的很多麻烦!!!希望大家都能征服智能指针,在C++的道路中走下去。💪💪💪