C++ unique_ptr简单使用
#######################智能指针(智能指针是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保在离开指针所在作用域时,自动正确的销毁动态分配的对象,防止内存泄漏)
头文件#include <memory>
unique_ptr特性 (属性为对象, 而不是指针, 管理指针)
(1).基于排他所有权模式:两个指针不能指向同一个资源
无法进行左值unique_ptr复制构造,也无法进行左值复制赋值操作,但允许临时右值赋值构造和赋值
保存指向某个对象的指针,当它本身离开作用域时会自动释放它指向的对象。
在容器中保存指针是安全的
无法进行左值复制赋值操作,但允许临时右值赋值构造和赋值, 结合std::move()使用, 将一个
(2). unique_ptr做为STL容器的元素时,不能作为类的成员变量; share_ptr可以作为类成员嵌套使用
例如:
class b{
private:
vector<unique_ptr<int>> temp; //错误
vector<unique_ptr<a>> tmp; //错误
}
(3). unique_ptr做为STL容器的元素时,不能直接进行传递,因为不可以进行拷贝和赋值操作.
vector<unique_ptr<int>> a;
a.push_back(new int(20)); //错误
a.emplace_back(new int(20)); //错误
a.emplace_back(make_unique<int>(20)); //错误
方法:
1. get(); // 返回对象管理的裸指针,带有风险性
2. release(); // 释放,调用后智能指针和其所指向对象的联系再无联系,但是该内存仍然存在有效。它会返回裸指针,但是该智能指针被置空。
返回的裸指针我们可以手工delete来释放,也可以用来初始化另外一个智能指针,或者给另外一个智能指针赋值。
3. reset();
reset()不带参数情况:释放智能指针所指向的对象(释放因为它是独占,而不像shared_ptr还需要考虑引用计数),并将智能指针置空。
reset()带参数时:释放智能指针所指向的对象,并将该智能指针指向新对象。
4. swap(); // 交换智能指针
例如:
unique_ptr<string> pointer(new string("123456"));
unique_ptr<string> pointer2(new string("888888"));
pointer = pointer2; // 非法, 禁止左值赋值操作
unique_ptr<string> pointer3(pointer2); // 禁止左值赋值构造
unique_ptr<string> p3(std::move(p1)); // 合法, std::move()将左值改变成右值
p1 = std::move(p2); // 使用move把左值转成右值就可以赋值了,效果和auto_ptr赋值一样
简单代码例子:
#include <iostream> #include <string> #include <memory> #include <stdio.h> #include <stdlib.h> #include <vector> using namespace std; class Absobj { public: Absobj() { printf("Create Abs - address: %p\n", this); } void print() { printf("Absobj print------\n"); } ~Absobj() { printf("~Del AbsObj - address: %p\n", this); } char *pBuf = nullptr; int m_num = 0; }; unique_ptr<Absobj> createPoint(int num) { unique_ptr<Absobj> ptr(new Absobj); printf("ptr: %p\n", &ptr); ptr->m_num = num; return ptr; } void dowork(std::unique_ptr<Absobj> &&ptr) { printf("ptr: %d\n", ptr->m_num); ptr->m_num = 888; } void gowork(std::unique_ptr<Absobj> ptr) { printf("-->ptr: %d\n", ptr->m_num); } void towork(std::unique_ptr<Absobj> &ptr) { printf(">>>ptr: %d\n", ptr->m_num); } int main(void) { vector<unique_ptr<Absobj>> vec; unique_ptr<Absobj> ptr(new Absobj); ptr->m_num = 123; printf("ptr address: %p | num: %d\n", &ptr, ptr->m_num); dowork(std::move(ptr)); // 二级引用做参数,操作的是本身,std::move不会释放智能指针对象 if ( ptr == nullptr ) { printf("Ptr is Null.\n"); } towork(ptr); // 引用传递,智能指针直接做为参数,可不用作为右值传递, if ( ptr == nullptr ) { printf("===Ptr is Null.\n"); } //gowork(std::move(ptr)); // 值传递, 不能直接传递左值(unique_ptr不支持拷贝赋值),只能转换成右值传递 if ( ptr == nullptr ) { printf(">>>Ptr is Null.\n"); } return 0; }
程序运行情况:
类中嵌套智能指针使用:
#include <iostream> #include <string> #include <memory> #include <stdio.h> #include <stdlib.h> #include <vector> #include <mutex> #include <list> #include <mutex> #include <algorithm> #include <memory> #include <atomic> #include <assert.h> using namespace std; // 自定义对象 class Test { public: Test(const string &str=string()) { cout << "Create Test" << endl; m_str = string("test") + str; } ~Test() { cout << "~Del Test()" << endl; } string m_str; }; class Son { public: Son(const string &str=string(), int num=0): m_str(std::move(str)) , m_num(num) { printf("Create Son\n"); m_unptr.reset(new Test(str)); } ~Son() { printf("~Del Son\n"); } string m_str = string(); int m_num = 0; unique_ptr<Test> m_unptr; }; /** * @brief The DataMng class 增删改查 */ class DataMng { public: DataMng(){} void add(const string &str, int num) { m_uniptrVec.push_back(unique_ptr<Son>(new Son(str, num))); } // 根据条件删除指定的对象 void del(int num) { for ( auto iter = m_uniptrVec.begin(); iter != m_uniptrVec.end(); ) { if ( (*iter).get() == nullptr ) continue; if ( (*iter)->m_num == num ) { printf("earse address: %p | num: %d | str: %s\n", (*iter).get(), (*iter)->m_num, (*iter)->m_str.c_str()); iter = m_uniptrVec.erase(iter); }else { iter++; } } } // 直接删除指定对象 void del(unique_ptr<Son> &ptr) { auto iter = std::find(m_uniptrVec.begin(),m_uniptrVec.end(), ptr); if ( iter != m_uniptrVec.end() ) { printf("del.\n"); iter = m_uniptrVec.erase((iter)); } } // 删除全部 void del() { auto iter = m_uniptrVec.begin(); while( iter != m_uniptrVec.end() ) { iter = m_uniptrVec.erase(iter); } } // 更新数据 void update(int num, const string &str) { for ( auto iter = m_uniptrVec.begin(); iter != m_uniptrVec.end(); ) { if ( (*iter).get() == nullptr ) continue; if ( (*iter)->m_num == num ) { (*iter)->m_str = str; (*iter)->m_unptr->m_str= str; break; }else{ iter++; } } } // 根据条件查找智能指针对象的裸指针(返回裸指针, 有风险) Son *find(int num) { for ( auto iter = m_uniptrVec.begin(); iter != m_uniptrVec.end(); ) { if ( (*iter).get() == nullptr ) continue; if ( (*iter)->m_num == num ) { return (*iter).get(); // 返回裸指针, 有风险 }else{ iter++; } } return nullptr; } // 智能指针容器 vector<unique_ptr<Son>> &uniptrVec() { return m_uniptrVec; } // 打印信息 void printVec() { for ( auto &obj: m_uniptrVec ) { printf("address: %p | num: %d | str: %s | tstr: %s\n", obj.get(), obj->m_num, obj->m_str.c_str(), obj->m_unptr.get()->m_str.c_str()); } printf("\n"); } private: vector<unique_ptr<Son>> m_uniptrVec; }; /** * @brief main 智能指针测试 * @return */ int main(void) { DataMng dataMng; printf(">>>>>>>>>>>>>>>>Add\n"); // 增 for (int i=0; i<4; i++) { dataMng.add(std::to_string(i), i); } dataMng.printVec(); // 改 printf(">>>>>>>>>>>>>>>>Changed\n"); dataMng.update(2, string("88888888")); dataMng.printVec(); // 查 printf(">>>>>>>>>>>>>>>>Find\n"); auto ptr = dataMng.find(2); printf("find ptr: %p | num: %d | str: %s\n", &ptr, ptr->m_num, ptr->m_str.c_str()); dataMng.update(ptr->m_num, string("22222222")); dataMng.update(1, string("1111111111111")); dataMng.printVec(); // 删 printf(">>>>>>>>>>>>>>>>Del\n"); dataMng.del(dataMng.uniptrVec()[0]); dataMng.printVec(); dataMng.del(1); dataMng.printVec(); printf("End uniptrVec.size: %d\n", (int)dataMng.uniptrVec().size()); return 0; }
执行结果:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!