c++智能指针(unique_ptr)
2022-11-13 本文已影响0人
arkliu
在c++11中通过引入只能指针的概念,使得c++程序猿不需要手动释放内存
智能指针的分类
- std::unique_ptr
- std::shared_prt
- std::weak_ptr
注意:
std::auto_ptr已被废弃
unique_ptr
- unique_ptr 在任何给定的时刻,只能由一个指针管理内存
- 当指针超出作用域时,内存将自动释放
- 该类型指针不可copy,只能move
unique_ptr的三种创建方式
-
通过已有裸指针创建
-
通过new创建
-
通过std::make_unique创建(推荐)
-
unique_ptr可以通过get()获取地址
-
unique_ptr实现了->与*
即可以通过->调用成员函数
可以通过* 调用解引用
unique_ptr创建
cat.h
#ifndef CAT_H
#define CAT_H
#include<string>
#include<iostream>
using namespace std;
class Cat {
public:
Cat(string name);
Cat() = default;
~Cat();
void cat_info()const{
cout << "cat ino name:"<<name << endl;
}
string get_name() const {
return name;
}
void set_name(const string &name) {
this->name = name;
}
private:
string name{"mimi"};
};
#endif
cat.cpp
#include "cat.h"
Cat::Cat(string name) :name(name) {
cout << "constructor of cat " << name<< endl;
}
Cat::~Cat() {
cout << "Deconstructor of cat " << name << endl;
}
#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main() {
// 栈上分配
Cat c1("ok");
c1.cat_info();
// 堆上分配,裸指针
Cat * c_cp1 = new Cat("yy");
c_cp1->cat_info();
delete c_cp1;
//------第一种 用已经存在的地址初始化智能指针 不推荐-----
Cat * c_p2 = new Cat("tts");
unique_ptr<Cat> uc_p2(c_p2);
uc_p2->cat_info();
//------第二种-----
unique_ptr<Cat>uc_p3{new Cat("dd")};
uc_p3->cat_info();
uc_p3->set_name("oo");
uc_p3->cat_info();
//------第三种 c++14标准 推荐使用-----
unique_ptr<Cat>uc_p4 = make_unique<Cat>();
uc_p4->cat_info();
uc_p4->set_name("oo");
uc_p4->cat_info();
return 0;
}
get()方法返回裸指针
#include<iostream>
#include<string>
#include<memory>
using namespace std;
class Test {
};
int main() {
Test* test = new Test(); // 定义原始指针test,并分配内存
unique_ptr<Test>test_ptr(test); // 创建智能指针test_ptr,用于管理原始指针test
cout << " 裸指针的值:" << test << endl;
cout << "test_ptr.get()的值:" << test_ptr.get() << endl;
cout << " test_ptr的地址:" << &test_ptr << endl;
return 0;
}
image.png
函数调用与unique_ptr
- 值传递
需要用std::move来转移内存的拥有权
如果参数直接传入std::make_unique语句,自动转换为move
void do_with_cat_pass_value(unique_ptr<Cat> c) {
c->cat_info();
}
unique_ptr<Cat>uc_p1 = make_unique<Cat>("hello..");
do_with_cat_pass_value(std::move(uc_p1));
do_with_cat_pass_value(make_unique<Cat>("world.."));
- 引用传递
如果设置参数为const则不能改变指向
比方说reset() - reset()方法为智能指针清空方法
void do_with_cat_pass_ref(unique_ptr<Cat> &c) {
c->set_name("hhhhhhh");
c->cat_info();
c.reset();
}
unique_ptr<Cat>uc_p2 = make_unique<Cat>("hello..");
do_with_cat_pass_ref(uc_p2);
cout << "uc_p2 address is :"<<uc_p2.get()<<endl;
image.png
- 值返回
指向一个local object
可以用做链式函数
unique_ptr<Cat> get_unique_ptr() {
unique_ptr<Cat> p_cat = make_unique<Cat>("nmnm");
return p_cat;
}
get_unique_ptr()->cat_info();
用nullptr赋值给unique_ptr将释放对象
#include <iostream>
#include <memory>
#include<string>
using namespace std;
class Cat {
public:
Cat(string name);
Cat() = default;
~Cat();
void cat_info()const{
cout << "cat ino name:" << name << endl;
}
string get_name() const {
return name;
}
void set_name(const string &name) {
this->name = name;
}
private:
string name{"mimi"};
};
Cat::Cat(string name) :name(name) {
cout << "constructor of cat " << name<< endl;
}
Cat::~Cat() {
cout << "Deconstructor of cat " << name << endl;
}
int main() {
unique_ptr<Cat> pu(new Cat("tony"));
cout <<"赋值前:"<<endl;
if (pu != nullptr)
{
cout <<"pu 不是空的"<<endl;
}
pu = nullptr;
if (pu == nullptr)
{
cout <<"pu 是空的"<<endl;
}
return 0;
}
image.png
release释放对原始指针的控制权
release释放对原始指针的控制权,将unique_ptr置为空,返回裸指针
// 函数fun1需要使用指针,但是不对这个指针负责
void fun1(const Cat* cat_ptr) {
cout << cat_ptr->get_name() << endl;
}
// 函数fun2需要使用指针,并且会对这个指针负责
void fun2(const Cat* cat_ptr) {
cout << cat_ptr->get_name() << endl;
delete cat_ptr;
}
// 函数fun3需要使用指针,但是不对这个指针负责
void fun3(const unique_ptr<Cat> &cat_ptr) {
cout << cat_ptr->get_name() << endl;
}
// 函数fun4需要使用指针,并且会对这个指针负责
void fun4(const unique_ptr<Cat> cat_ptr) {
cout << cat_ptr->get_name() << endl;
}
int main() {
unique_ptr<Cat> pu(new Cat("tony"));
// fun1(pu.get());
// fun2(pu.release());
fun4(std::move(pu));
if (pu == nullptr)
{
cout <<"pu 是空指针"<<endl;
}
return 0;
}
reset()释放对象
pp.reset() //释放pp对象指向的资源对象
pp.reset(nullptr) //释放pp对象指向的资源对象
pp.reset(new Cat("jerry")) //释放pp对象指向的资源对象,同时指向新对象
swap() 交换两个unique_ptr的控制权
void swap(unique_ptr<T> &right);
unique_ptr不是绝对安全
unique_ptr不是绝对安全,如果程序调用exit()退出, 全局的unique_ptr可以自动释放,但是局部的unique_ptr无法释放。
unique_ptr<Cat> pu(new Cat("全局的猫"));
int main() {
unique_ptr<Cat> pu(new Cat("局部的猫"));
return 0;
//exit(0);
}
此时程序结束,全局的和局部的都被释放了
image.png
将上面的退出方式,改为exit,局部的对象就不会被释放
image.png
unique_ptr支持数组
int main() {
// unique_ptr<Cat[]> pu(new Cat[2]);
unique_ptr<Cat[]> pu(new Cat[2] {string("狸猫"), string("家猫")});
cout << pu[0].get_name() << "===" << pu[1].get_name()<< endl;
return 0;
}
image.png