c++ unique_ptr
智能指针概述
C++的指针包括原始指针和智能指针两种,智能指针是原始指针的封装,其优点是可以自动分配内存,无需担心内存的泄露。
并不是所有的指针都可以封装为智能指针,很多时候原始指针要更方便;
各种指针里,原始指针最常用,其次是unique_ptr和shared_ptr,weak_ptr是对shared_ptr的补充,应用场景较少。
智能指针只能解决一部分问题:独占/共享所有权指针的释放和传输;并没有从根本上解决C++的内存泄漏问题
独占指针 unique_ptr
在给定的时刻,只能有一个指针管理内存,当指针超出作用域后,内存自动释放
该类型指针不可Copy,只可以Move
uniqueptr是智能指针的一种,主要用于C++的内存申请和释放,因为C++在申请内存后,要手动进行delete,这样就会出现有时候忘记delete,或者return,break,异常等原因没有执行到delete,不知道什么时候delete内存,所以引入uniqueptr指针,当指针销毁不时,自动删除指针指向的内存。unique_ptr的特点是只允许一个指针指向这块内存,unique_ptr赋值操作是不允许的,例如uniqueptr1=uniqueptr2;是不允许的,只能通过转移,uniqueptr1=move(uniqueptr2);将uniqueptr2指向的内存转移给uniqueptr1。
- unique_ptr可以通过get获取地址,
- 通过->调用成员函数,
- 通过* (解引用)
创建方式
(1)通过已有的裸指针创建(建议裸指针设为空,并且及时销毁,不推荐)
示例:
#include <stdio.h> #include <iostream> #include <algorithm> #include <vector> #include<Windows.h> using namespace std; //自定义数据类型 class Person { public: Person(string name, int age) { mName = name; mAge = age; } Person(); void Set_Name(string name) { this->mName = name; } void Info() { std::cout << "name:" << this->mName << endl; } public: string mName; int mAge; }; int main() { Person* p1 = new Person(); unique_ptr<Person> uc1{ p1 }; p1->Set_Name("哈哈"); uc1->Info(); // 这种方式需要再删除裸指针 delete p1; p1 = nullptr; uc1->Info(); system("pause"); return 0; } Person::Person() { }
(2)通过new创建
示例:
#include <stdio.h> #include <iostream> #include <algorithm> #include <vector> #include<Windows.h> using namespace std; //自定义数据类型 class Person { public: Person(string name, int age) { mName = name; mAge = age; } Person(); void Set_Name(string name) { this->mName = name; } void Info() { std::cout << "name:" << this->mName << endl; } public: string mName; int mAge; }; int main() { unique_ptr<Person> uc2(new Person); uc2->mAge = 11; uc2->mName = "uc2"; uc2->Info(); system("pause"); return 0; } Person::Person() { }
结果:
(3)通过std::make_unique创建(推荐)
示例:
#include <stdio.h> #include <iostream> #include <algorithm> #include <vector> #include<Windows.h> using namespace std; //自定义数据类型 class Person { public: Person(string name, int age) { mName = name; mAge = age; } Person(); void Set_Name(string name) { this->mName = name; } void Info() { std::cout << "name:" << this->mName << endl; } public: string mName; int mAge; }; int main() { unique_ptr<Person> uc2 =make_unique<Person>(); uc2->mAge = 11; uc2->mName = "uc2"; uc2->Info(); system("pause"); return 0; } Person::Person() { }
unique_ptr和函数调用
补充:还是尽量使用引用传递
值传递通过move方式实现
示例:
#include <stdio.h> #include <iostream> #include <algorithm> #include <vector> #include<Windows.h> using namespace std; //自定义数据类型 class Person { public: Person(string name, int age) { mName = name; mAge = age; } Person(); void Set_Name(string name) { this->mName = name; } void Info() { std::cout << "name:" << this->mName << endl; } public: string mName; int mAge; }; void pass_value(unique_ptr<Person> u) { u->mName = "值传递"; u->Info(); } int main() { unique_ptr<Person> uc2 = make_unique<Person>(); // 将指针uc2指向的内存转移给u,uc2变为空 pass_value(move(uc2)); // 下面代码报错,因为已经指向空了 //uc2->Info(); system("pause"); return 0; } Person::Person() { }
结果:
引用传递
示例:
#include <stdio.h> #include <iostream> #include <algorithm> #include <vector> #include<Windows.h> using namespace std; //自定义数据类型 class Person { public: Person(string name, int age) { mName = name; mAge = age; } Person(); void Set_Name(string name) { this->mName = name; } void Info() { std::cout << "name:" << this->mName << endl; } public: string mName; int mAge; }; // 加const,防止调用unique_ptr的函数,比如说reset,因为执行之后会清空u指向,并且销毁指向内存; void pass_ref(const unique_ptr<Person>& u) { u->mName = "值传递"; u->Info(); // 加const之后无法执行下面代码了 //u.reset(); } int main() { unique_ptr<Person> uc2 = make_unique<Person>(); pass_ref(uc2); uc2->Info(); system("pause"); return 0; } Person::Person() { }
结果:
还有一种定义别名的方式,这个纯粹是看个人的代码风格了
#include <stdio.h> #include <iostream> #include <algorithm> #include <vector> #include<Windows.h> using namespace std; //自定义数据类型 class Person { public: Person(string name, int age) { mName = name; mAge = age; } Person(); void Set_Name(string name) { this->mName = name; } void Info() { std::cout << "name:" << this->mName << endl; } // 在这里定义一个unique_ptr的别名UniquePtr using UniquePtr = unique_ptr<Person>; public: string mName; int mAge; }; // 加const,防止调用unique_ptr的函数,比如说reset,因为执行之后会清空u指向,并且销毁指向内存; void pass_ref(const unique_ptr<Person>& u) { u->mName = "值传递"; u->Info(); // 加const之后无法执行下面代码了 //u.reset(); } int main() { Person::UniquePtr client = make_unique<Person>(); client->Info(); system("pause"); return 0; } Person::Person() { }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?