三种智能指针

news2024/9/26 1:28:19

智能指针

new和delete

1:new初始化
  • new未初始化值
    int *p = new int;//p值未定义
    string *str = new string;//为空串,调用string默认构造函数
  • new 初始化值
    int *p = new int(100);
    string *str = new string(6,'a');//aaaaaa
  • vector类型指针
 vector<int> *p = new vector<int>{1, 3, 5, 7, 9};
    vector<int> mm{9, 8, 7, 6};
    vector<int> *nn = &mm;
    for (int i = 0; i < p->size();i++){
        cout << p->at(i) << ",";
    }
    for (int i = 0; i < nn->size();i++){
        cout << nn->at(i) << ",";
    }

注意:

vector<int> *p = new vector<int>{1, 3, 5, 7, 9};
//p->size()与(*p).size()等价
//p->at(i)等价于(*p).at(i)等价于(*p)[i]
 for (int i = 0; i < p->size();i++){
        cout << (*p).at(i)<< ",";
 }
2:值初始化
    string *mystr = new string();//空字符串
    int *p = new int();//赋值0

如果是类的值初始化,调用类的构造函数

class A{
public:
    A(){
        cout << "call()" << endl;
    }
};
int main(){
    A *a = new A();
    return 0;
}

运行结果:call()

不加()效果一样: A *a = new A;

  • new和auto的配合使用
    string *s = new string(7, 'a');
    //这里s是指针,所以auto的类型是string*
    auto *mystr = new auto(s);
    //string **mystr = new string *(s);
    cout << (*mystr)->c_str() << endl;
    //cout << *(*mystr)<< endl;
  • const可以和new配合使用
const int *p = new const int(200);
//const int *p = new int(200);---new后可以不加const

const修饰的p指针不可以改变 *p=200;是错的

3:delete

new和delete是配合使用的,delete用于回收new分配出的内存空间,而且delete只能使用一次去释放内放

注意:delele只能释放new分配的空间

 int i = 100;
 int *p = &i;
 delete p;//报错:p指向的内存不是new出来的

多个指针指向同一块内存,没必要重复delete

 int *p = new int(100);
 int *p2 = p;//p和p2指向同一块内存
 delete p;//输出*p2会出错
 delete p2;//没必要多次释放

总结
  1. new出来的必须delete,不然内存泄漏,会导致程序崩溃
  2. delete后的内存不能再次使用
  3. 不要对同一个内存多次delete
 int* p = new int(9);
 delete p;
 *p = 300;//释放之后使用会出错,最好置成NULL
 //p=NULL;
 cout << *p << endl;
  • new和delete都是运算符,不是函数。

  • new和delete相比于malloc和free可以干更多事

    —在堆上分配一个对象时,new和delete会自动调用类的构造和析构函数

    也就是存在初始化能力,malloc和free没有这个能力

😄A a; sizeof(a);---------空类的对象也占有一个字节,因为空类对象有地址,至少在内存占一个字节


4:operator new()和operator delete()

new运算符会分配内存调用构造函数,这里分配内存就是调用operator new()函数

delete运算符会调用析构函数然后释放内存operator delete()(顺序和new相反)

5:申请和释放数组
 int *p = new int[2];//中括号是数组,分配两个数据

class A{
public:
   A(){}
};
int main(){
    A *pa = new A[2]();
    delete[] pa;//别忘【】
}

内置类型,比如:int,double,delete时候不需要调用析构函数

int *pa=new int[4];

delete pa;delete[] pa;是一样的,因为int是内置类型,不需要析构函数。


如果是自定义类对象,用new分配了一个对象数组:A *a=new A[3] ();

这时候如果类存在自定义析构函数,必须用delete[]释放

注意:new的不是数组,也不要用delete[]。

智能指针总述

前提:new和delete非常容易出错

比如忘记delete

int *p=new int;
if(con){
    return;//提前返回
}
delete p;

或者提前释放

比如:delete后的指针依然被继续使用

裸指针是直接new出来的指针

智能指针:对裸指针进行了包装,最突出的优点就是自动释放new的对象内存

四种智能指针:

    auto_ptr;//完全被unique_ptr取代,被摒弃
    /*新标准c++11的三种智能指针都是类模板,可以给它们赋值new获得的地址*/
    unique_ptr;----独占指针,同一时间内只有一个指针指向该对象。但是可以把所有权移交。
    shared_ptr;----多个指针指向同一对象,最后一个指针被销毁,对象才被释放
    weak_ptr;----辅助shared_ptr使用

1:shared_ptr

共享所有权,不是被一个shared_ptr拥有,而是被多个shared_ptr相互协作,有额外开销。

工作原理:引用计数,每个shared_ptr的拷贝都指向相同的内存。

​ 所以最后一个指向该shared_ptr指针不再指向该对象时,这个shared_ptr才会去析构所指向的内存。

    shared_ptr<int> p1(new int(100));
    shared_ptr<int> p2 = new int(200);//×,只能显示赋初值()
//----------------------------------------------------------
shared_ptr<int> make(int val){
    return shared_ptr<int>(new int(val));
}
shared_ptr<int> p3 = make(300);

智能指针和裸指针不要穿插使用

 int *p = new int;
 shared_ptr<int> ptr(p);//不要这么使用
 shared_ptr<int> ptr(new int);//可以
make_shared()创建对象

标准库里的函数模板,能够高效的分配和使用share_ptr,别忘了匹配参数<类型>

但是make_shared()不能指定删除器

 shared_ptr<int> p = make_shared<int>(100);
 shared_ptr<string> s = make_shared<string>(10,'a');
shared_ptr的引用参数

当进行赋值或拷贝时,每个shared_ptr都会有一个引用参数,用来记录有多少个指向同一内存的其他shared_ptr对象

引用参数其实就是一个计数器,用来记录当前指向同一个内存的shared_ptr的个数

1.引用计数的增加
 auto p1 = make_shared<int>(100);//创建一个shared_ptr,p1引用计数为1
 shared_ptr<int> p2(p1);//用p1给p2拷贝,p1和p2此时引用计数为2
 auto p3 = p2;//p2给p3赋值,p1,p2,p3引用计数为3

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

函数非引用传参,在函数体内引用参数+1

void myfun(shared_ptr<int> tmp) {
 return;
}
int main() {
 auto p1 = make_shared<int>(100);//创建一个shared_ptr,p1引用计数为1
 myfun(p1);
}

在这里插入图片描述

如果传的是引用,那么引用参数不增加

void myfun(shared_ptr<int>& tmp) {//引用
    return;
}
int main() {
    auto p1 = make_shared<int>(100);//创建一个shared_ptr,p1引用计数为1
    myfun(p1);
}

在这里插入图片描述

  • 接受make_shared返回值,引用参数加1
shared_ptr<int> getPtr(shared_ptr<int>& p) {
 return p;
}
int main() {
 auto p1 = make_shared<int>(100);//创建一个shared_ptr,p1引用计数为1
 auto p2 = getPtr(p1);
 getPtr(p2);//临时对象没有参数接收,执行后引用参数不增加
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.引用计数的减少
  1. 局部的值传递shared_ptr离开作用域

  2. shared_ptr指向了新对象

auto p1 = make_shared<int>(100);
auto p2 = getPtr(p1);
auto p3 = p2;
/*指针指向新对象,引用计数-1*/
p1 = make_shared<int>(33);

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 当一个shared_ptr的引用计数从1变为0,智能指针自动释放
 auto p1 = make_shared<int>(20);
 auto p2 = make_shared<int>(30);
 p1 = p2;//p1和p2引用计数为2,原来p1的内存被释放
shared_ptr指针常用操作
  • use_count()—返回指向某个对象的引用计数
shared_ptr<string> ptr(new string(5, 'a'));
int cnt = ptr.use_count();//1
shared_ptr<string> p2(ptr);
cout << ptr.use_count();//2
shared_ptr<string> p3 = p2;
cout << ptr.use_count();//3
  • unique()----该智能指针是否独占对象

为空也不行,必须use_count()为1

  shared_ptr<string> ptr(new string(5, 'a'));
  cout << ptr.unique() << endl;//真
  shared_ptr<string> p2(ptr);
  cout << p2.unique() << endl;//假
  • reset()—复位
    1. 不带参数,把唯一指向该对象的指针的内存释放,并把指针置空。
    2. 不带参数,但是多个指向该对象,把引用计数-1,并把指针置空。
   shared_ptr<string> ptr(new string(5, 'a'));
   shared_ptr<string> p2(ptr);
   p2.reset();
   if (p2 == nullptr) {
       cout << "p2 is NULL" << endl;
   }
   cout << ptr.use_count() << endl;
  1. 带参数,把唯一指向该对象的指针的内存释放,并把指针指向新对象。
  2. 带参数,但是多个指向该对象,把引用计数-1,并把指针指向新对象。

shared_ptr<int> p1(new int(100));
p1.reset(new int(200));`

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  shared_ptr<int> p1(new int(100));
  auto p2(p1);
  p1.reset(new int(200));
  if (p1.unique()) {
      cout << "p1 is unique;" << endl;
  }
  if (p2.unique()) {
      cout << "p2 is unique;" << endl;
  }

空指针也可以用reset()初始化

shared_ptr p1;***
p1.reset(new int(30));***

  • 解引用—获得指针指向的对象

用法同普通指针

    shared_ptr<int> p1=make_shared<int>(99);
    cout << *p1 << endl;//99
    shared_ptr<string> p2 = make_shared<string>(5, 'a');
    cout << *p2 << endl;//aaaaa
  • get()—返回保存的指针,小心使用,如果释放了所指向对象,指针无效

说白了返回裸指针,这个函数目的就是某些第三方函数传参只能使用裸指针

shared_ptr<int> p = make_shared<int>(99);
int* ptr = p.get();
cout << *ptr << endl;//99
//千万不能delete该裸指针
  • swap()----交换两个对象内容
	shared_ptr<string> p1 = make_shared<string>("aaabbb");
	shared_ptr<string> p2(new string("cccddd"));
	swap(p1, p2);
	cout << *p1 <<","<< * p2 << endl;
	p1.swap(p2);
	cout << *p1 << "," << *p2 << endl;
  • =nullptr----置空
	shared_ptr<string> p1 = make_shared<string>("aaabbb");
	shared_ptr<string> p2(p1);
	p1 = nullptr;
	//p1是空指针,p2指向aaabbb且引用计数为1
	if (!p1) {
		cout << "空指针" << endl;
	}
shared_ptr指定删除器(自定义删除)

在参数中指定删除器函数名即可,自己必须delele对象,不然内存泄漏。

注意make_shared这种方式不能指定删除器

可以用lambda表达式

shared_ptr<int> p1(new int(100), [](int* p) {
	cout << "****" << endl;
	delete p;
});//加入参数
//当引用计数为0,自动调用该函数
void myDelete(int* p) {
	cout << "call myDelete!" << endl;
	delete p;
}
int main() {
	shared_ptr<int> p1 (new int(100),myDelete);//加入参数
	auto p2(p1);
	p2.reset();
	p1 = nullptr;
}

用shared_ptr管理动态数组,只能自己释放

shared_ptr<int> p1(new int[10], [](int* p) {
	delete[] p;
});//加入参数
//shared_ptr<A> ptr(new A[5]);//系统释放异常。系统delete是ptr的裸指针。
shared_ptr<A> ptr(new A[5], [](A* p) {
	delete[] p;
});

可以用default_delete来释放,<>指定数组

shared_ptr<A> ptr(new A[5], default_delete<A[]>());

在最开始加个[]就可以正常释放数组

	shared_ptr<A[]>  ptr(new A[5]);
	shared_ptr<int[]> p(new int[3]{1,2,3});
	cout << p[2] << endl;//加了[]可以下标访问

函数模板来定义数组

template<typename T>
shared_ptr<T> make_arr(size_t sz) {
	return shared_ptr<T>(new T[sz], default_delete<T[]>());
}
int main() {
	shared_ptr<int > p1= make_arr<int>(3);
	shared_ptr<string > p2 = make_arr<string>(4);
}

注意:就算两个shared_ptr指定了不同的删除器,只要指向的对象类型相同,这两个shared_ptr也是一个类型

类型相同就是可以用同一个容器装

shared_ptr<int> p1(new int(100), f1);
shared_ptr<int> p2(new int(200), f2);
vector<shared_ptr<int>> vec{ p1,p2 };
	auto f1 = [](int *p) {
		cout << "f1()" << endl;
		delete p;
	};
	auto f2 = [](int* p) {
		cout << "f2()" << endl;
		delete p;
	};
	shared_ptr<int> p1(new int(100), f1);
	shared_ptr<int> p2(new int(200), f2);
	p2 = p1;//p2指向其他,调用f2释放自己对象,p1的引用计数+1
	//最后执行结束前,p2和p1用f1释放

2:weak_ptr

weak_ptr用来辅助shared_ptr<进行工作

  • 强指针就是:shared_ptr
  • 弱指针就是:weak_ptr

weak_ptr也是一个类模板构造的智能指针,weak_ptr指向一个由shared_ptr管理的对象

❗️❗️注意❗️❗️

  • weak_ptr这种智能指针不控制所指向的对象的生命周期

​ 如果shared_ptr和weak_ptr指向同一对象,或者说将weak_ptr绑定到shared_ptr上,并不会改变shared_ptr的引用计数。即:weak_ptr的构造和析构不能增加或减少所指向对象的引用计数。

弱引用weak_ptr是监视shared_ptr生命周期用的,weak_ptr不是一种独立的智能指针,不能用来操作所指向的资源。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注意:只有强引用才能影响对象的生命周期

/*一般用一个shared_ptr来初始化weak_ptr*/
shared_ptr<int> ps = make_shared<int>(100);
weak_ptr<int> ps_w(ps);
//弱引用赋值给弱引用
weak_ptr<int> ps_w2 = ps_w;
lock()

因为weak_ptr指向的对象的声明周期可能结束了,所以weak_ptr使用对象前,必须判断对象是否存在

lock()就是检查weak_ptr指向的对象是否存在

  • 如果存在,lock()返回一个该对象的shared_ptr,此时引用计数+1
  • 如果不存在,lock()返回一个空的shared_ptr
int main() {
	/*一般用一个shared_ptr来初始化weak_ptr*/
	shared_ptr<int> ps = make_shared<int>(100);
	weak_ptr<int> ps_w(ps);
	//pi接受ps_w指向对象的强引用
	auto pi = ps_w.lock();
	if (pi) {
		*pi = 99;//改变值
	}
	else {
		cout << "no duixiang!!" << endl;
	}
	cout << *ps << endl;//99,改变值成功
}
int main() {
	/*一般用一个shared_ptr来初始化weak_ptr*/
	shared_ptr<int> ps = make_shared<int>(100);
	weak_ptr<int> ps_w(ps);
	//pi接受ps_w指向对象的强引用
	ps.reset();//减少一个强引用,此时指向的对象被释放
	auto pi = ps_w.lock();
	if (pi) {
		*pi = 99;//改变值
	}
	else {
		cout << "no duixiang!!" << endl;
	}
}

也就是weak_ptr可以判断指向对象存在性

use_count()

获取weak_ptr的强引用计数

int main() {
	auto p1 = make_shared<int>(11);//p1是shared_ptr
	auto p2(p1);//p2是shared_ptr
	weak_ptr<int> pw(p1);
	cout << pw.use_count() << endl;//2
}
expired()

是否过期的意思,弱指针的use_count为0时候返回true。也就是判断指向对象的存在性

int main() {
	auto p1 = make_shared<int>(11);//p1是shared_ptr
	auto p2(p1);//p2是shared_ptr
	weak_ptr<int> pw(p1);
	p1.reset();
	p2.reset();
	if (pw.expired()) {
		cout << "对象已经过期" << endl;
	}
}
reset()

将弱引用指针涉为空,弱引用计数-1

int main() {
	auto p1 = make_shared<int>(11);//p1是shared_ptr
	auto p2(p1);//p2是shared_ptr
	weak_ptr<int> pw(p1);
	p1.reset();
	pw.reset();//执行后,p2指向对象没有弱引用
	cout << *p2 << endl;//11
}

综合使用

int main() {
	auto p1 = make_shared<int>(100);
	weak_ptr<int> pw = p1;
	if (!pw.expired()) {//pw对象存在
		auto p2 = pw.lock();
		if (p2) {
			cout << p2.use_count() << endl;
		}
	}
	//p2离开了作用域,引用计数-1
	cout <<"***"<< p1.use_count() << endl;
}

运行结果:

2
***1

智能指针尺寸

C++的一个指针占内存几个字节?
----在64位编译模式下,指针的占用内存大小是8字节
----在32位编译模式下,指针占用内存大小是4字节

智能指针大小是普通指针的两倍

	int* p;
	shared_ptr<int> ps;
	weak_ptr<int> pw;
	cout << sizeof(p) << endl;
	cout << sizeof(ps) << endl;
	cout << sizeof(pw) << endl;

运行结果:

8
16
16

智能指针内部包含两个裸指针

  • 一个指针指向对象
  • 第二个指针指向控制块(一个很大的数据结构)
    • 控制块有:强引用计数,弱引用计数,其他数据比如自定义删除器

❗️其中❗️:

  • shared_ptr创建控制块,weak_ptr指向控制块

  • 这个控制块是第一个创建shared_ptr的对象创建

    make_share():一定可以创建出一个控制块

    裸指针可以创建一个控制块(但是不要用裸指针初始化多个)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

❗️shared_ptr使用深入

利用函数创建shared_ptr

//从函数中return shared_ptr
shared_ptr<int> create_ptr(int val){
	return make_shared<int>(val);
}
//利用对象来接shared_ptr,返回对象
shared_ptr<int> myPtr(int val){
	shared_ptr<int> tmp = create_ptr(val*2);
	//系统根据tmp这个局部变量产生一个临时变量往回返
	return tmp;
}
int main(){
	shared_ptr<int> p1 = create_ptr(100);
	shared_ptr<int> p2 = myPtr(200);
	cout << *p1 << "," << *p2 << endl;
}

shared_ptr使用陷阱

  1. 慎用裸指针
void profun(shared_ptr<int> ptr){
	cout << ptr.use_count() << endl;
	return;
}
int main(){
	int *p = new int(11);
	shared_ptr<int> p2(p);
	//profun(p);--注意裸指针和智能指针不存在隐式转换
	profun(p2);
	*p = 300;
	//利用裸指针创建的智能指针后续值会变化
	cout << *p << "," << *p2 << endl;//300,300
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

而且利用裸指针创建的智能指针,后续值会随着裸指针变化。所以最好后续不要用裸指针

void profun(shared_ptr<int> ptr){
	cout << ptr.use_count() << endl;
	return;
}
int main(){
	int *p1 = new int(11);
	//这样临时对象传入函数,引用计数不+1,所以return后内存释放
	profun(shared_ptr<int>(p1));
	cout << *p1 << endl;
	shared_ptr<int> p2(new int(100));
	//但是直接创建智能指针,传入函数引用计数+1
	profun(p2);
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

发现p1内存异常,因为临时对象传入profun()不会增加引用计数,所以函数运行结束内存会释放

但是直接传入shared_ptr,引用计数会增加,不会影响主程序的p2

不要用裸指针初始化多个shared_ptr

	int *p1 = new int(11);
	shared_ptr<int> p2(p1);
	shared_ptr<int> p3(p1);
	//1,1
	cout << p2.use_count() << "," << p3.use_count() << endl;

发现p2,p3不会增加引用计数,所以释放时候会delete2次,会异常

  1. 慎用get()返回的指针

❗️get返回的是智能指针中的裸指针,这个指针不能delete

	shared_ptr<int> p(new int(100));
	int* pm = p.get();
	//pm虽然得到了p的指针,但是内存管理还是归智能指针
	//裸指针不可以释放内存
	delete pm;

❗️不能将其他智能指针绑定到get的裸指针

这就是不增加引用计数,会delete多次

	shared_ptr<int> p(new int(100));
	int* pm = p.get();
	shared_ptr<int> q(pm);
	//都是1,因为这样和绑定裸指针一样,不增加引用计数
	cout << p.use_count() << "," << q.use_count();

get的裸指针不能delete而且也不用该指针赋值或初始化

  • 不要把类指针this作为shared_ptr返回,改用enable_shared_from_this
class CT {
public:
	shared_ptr<CT> getself() {
		return shared_ptr<CT>(this);
	}
};
int main(){
	shared_ptr<CT> pt(new CT);
	shared_ptr<CT> p2 = pt;
}

这样p2,pt的引用计数都是2

class CT {
public:
	shared_ptr<CT> getself() {
		return shared_ptr<CT>(this);
	}
};
int main(){
	shared_ptr<CT> pt(new CT);
	//说白了this也是类的裸指针,初始化了多个对象
	//这里引用计数不增加
	shared_ptr<CT> p2 = pt->getself();
	cout << p2.use_count() << endl;
}

它们指向同一内存但是不是同样的内存块

enable_shared_fron_this是类模板

//公有继承了enable_shared_from_this模板
class CT :public enable_shared_from_this<CT>{
public:
	shared_ptr<CT> getself() {
		return shared_from_this();//模板中的方法
	}
};
int main(){
	shared_ptr<CT> pt(new CT);
	shared_ptr<CT> p2 = pt->getself();
	cout << p2.use_count() << endl;
}

这样就可以增加引用计数了

原理就是:enable_shared_from_this里面有一个弱指针,这个弱指针指向this,然后每次创建新对象就会调用lock(),保证了shared_ptr的引用计数增加

移动语义

	shared_ptr<int> p1(new int(100));//p1地址:0x000001f36d6d0850
	//这样p1为空,p2指向了内存
	shared_ptr<int> p2(move(p1));//p2地址:0x000001f36d6d0850
	/*move函数:让p2接管了p1的地址,然后把p1置空*/
	shared_ptr<int> p3;
	p3 = move(p2);//同样p3接管p2,p2置空
	if (!p2) {
		cout << "p2 id NULL" << endl;
	}

shared_ptr还有分配器,涉及内存分配。

//使用make_shared更高效
shared_ptr<string> p1(new string("good for you"));//分配两次内存
shared_ptr<string> p2=make_shared("good for you");//释放一次内存

3:unique_ptr

unique_ptr是独占对象,所以同一时间只能由一个unique_ptr指向对象

unique_ptr被销毁的时候,它所指向的对象也会被销毁

初始化
int main() {
    unique_ptr<int> p;
    if (p == nullptr) {
        cout << "p是空指针" << endl;
    }
    unique_ptr<int> p2(new int(100));
    //c++14才有make_unique(),这个创建不能指定删除器
    unique_ptr<int> p3 = make_unique<int>(200);
    cout << *p2 << "," << *p3 << endl;
}
unique_ptr不支持的操作

核心就是unique_ptr独占内存

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

移动语义

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

release()

将智能指针和对象联系切断,放弃指针的控制权。返回裸指针,然后把智能指针置空

返回的裸指针可以delete也可以给其他指针赋值

	unique_ptr<string> p1 = make_unique<string>("good luck");
	//p2接管p1,p1置空
	unique_ptr<string> p2(p1.release());
	if (p1 == nullptr) {
		cout << "p1被置空" << endl;
	}
	p2.release();
	//如果没有delete那么内存泄露

正确释放

	string* tmp=p2.release();
	delete tmp;
reset()
  • reset()无参数----释放智能指针指向的对象并将智能指针置空
  • reset()带参数----释放智能指针指向的对象并将智能指针指向新对象
	unique_ptr<string> p1 = make_unique<string>("good luck");
	unique_ptr<string> p2 = make_unique<string>("hello world");
	p1.reset();
	if (p1 == nullptr) {
		cout << "p1被置空" << endl;
	}
	p1.reset(p2.release());//p2release后被置空,reset释放p1指向的内存,让p1指向p2的裸指针
	if (p1) {
		cout << *p1<< endl;
	}
	unique_ptr<string> p1 = make_unique<string>("good luck");
	p1.reset(new string("hello world"));
	cout << *p1 << endl;//hello world
	unique_ptr<string> p1 = make_unique<string>("good luck");
	//释放p1指向对象的内存
	//并将p1置空
	p1 = nullptr;
指向数组

一般不用,因为容器更好用

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

get()

返回智能指针的裸指针,但是要注意不要提前释放

	unique_ptr<string> up = make_unique<string>("hello,world");
	string* tmp = up.get();
	cout << *tmp << endl;

一般是作为库函数的函数接口参数

转换成shared_ptr
auto myfun() {
	return unique_ptr<string>(new string("hello, world"));
}
int main() {
	//注意:unique_ptr没有控制块
	//p在这里创建
	shared_ptr<string> p = myfun();
	unique_ptr<string> mm(new string("good,luck"));
	shared_ptr<string> nn = move(mm);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2089617.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pikepdf:一个实用的PDF文件处理Python库

我是东哥&#xff0c;今天给大家介绍一个实用的Python库——pikepdf&#xff0c;它能让你像操作文本文件一样轻松地处理PDF&#xff0c;无论是读取、修改还是保存&#xff0c;都能迎刃而解。 基本介绍 pikepdf是一个基于Python的库&#xff0c;它允许开发者轻松地读取、写入和…

第四课,接收键盘输入

一&#xff0c;关于基本框架中头文件的作用 头文件就是一个工具箱&#xff0c;C中有很多工具&#xff0c;我们最熟悉的cout就是其中之一 引入头文件&#xff1a;如果你想在你的代码中使用工具箱里的工具&#xff0c;C会很大方的让你用&#xff0c;但前提是你必须在本页代码的最…

为什么 CNC 加工会产生毛刺?

在现代机械加工领域&#xff0c;CNC(计算机数控)加工以其高精度、高效率的特点被广泛应用。然而&#xff0c;在 CNC 加工过程中&#xff0c;毛刺的产生常常是一个令人困扰的问题。时利和将解析为什么 CNC 加工会产生毛刺呢? 一、刀具磨损 刀具在长时间的使用过程中会逐渐磨损。…

如何一步快速去除黑神话悟空图片上的文字?一招教会你

设计师朋友们&#xff0c;如果老板让你用去除海报上的文字&#xff0c;你会怎么做&#xff1f; 用PS的内容识别填充&#xff0c;图片就会变模糊再精修简直太麻烦啦&#xff01; 还好我最近找到一个图片处理神器&#xff0c;一键就能P去图片的文字&#xff01;简单又高效&…

day04-面向对象-常用API时间Arrays

一、常用API 1.1 StringBuilder类 StringBuilder类代表可变的字符串对象&#xff0c;理解为一个操作字符串的容器相对于String来说,比本来的操作效率更高 ​ StringBuilder常用方法public StringBuilder(): 构建一个空的可变字符串对象public StringBuilder(String str): 构建…

vue3中vite基于vite-plugin-html的多入口打包

先看打包效果 1、安装vite-plugin-html 2、配置多个入口 每个入口都要有模板(index.html、App.vue、main.js复制一份&#xff0c;根据实际需求调整三个文件) 3、配置vite.config.js 4、代码片段 import { createHtmlPlugin } from vite-plugin-htmlconst htmlParams {minif…

关于springboot的Rest请求映射处理的源码分析(一)

我们在开发中很常见的一种方式是通过请求的类型&#xff0c;也就是restful风格来区别我们的请求接口。 通过请求类型的不同(GET POST PUT DELETE) 来区分即便是请求路径相同的请求。 但是他的底层是如何支持的呢&#xff0c;明明我请求路径都是/user。就因为类型不同就能区分到…

网络层 III(划分子网和构造超网)【★★★★★★】

&#xff08;★★&#xff09;代表非常重要的知识点&#xff0c;&#xff08;★&#xff09;代表重要的知识点。 一、网络层转发分组的过程 分组转发都是基于目的主机所在网络的&#xff0c;这是因为互联网上的网络数远小于主机数&#xff0c;这样可以极大地压缩转发表的大小。…

【Python报错】AttributeError`:`‘NoneType‘ object has no attribute ‘XXXX‘`

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引言 在Python编程中&#xff0c;AttributeError是一个常见的错误类型&#xff0c;它表示尝试访问的对象没有该属性。本文将探讨…

深度强化学习算法(六)(附带MATLAB程序)

深度强化学习&#xff08;Deep Reinforcement Learning, DRL&#xff09;结合了深度学习和强化学习的优点&#xff0c;能够处理具有高维状态和动作空间的复杂任务。它的核心思想是利用深度神经网络来逼近强化学习中的策略函数和价值函数&#xff0c;从而提高学习能力和决策效率…

CNN网络的一些基本知识

CNN 网络的layer介绍 在卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;中&#xff0c;往往包含许多种不同的网络层交替组成&#xff0c;主要有卷积层&#xff08;Convolutional Layer&#xff09;、池化层&#xff08;Pooling Layer&#…

《黑神话:悟空》爆火,对程序员的 5 点启示(2)

前言 继续上篇未完章节…… 4. 需求捕捉 需求有真需求和伪需求的区别&#xff0c;捕捉和理解用户的真需求对于产品非常重要。 在《黑神话&#xff1a;悟空》面世以后&#xff0c;很多玩家都不吝称赞&#xff0c;有玩家这么评论&#xff1a; 不吹牛逼&#xff0c;这一段我眼…

C#中通过TabControl控制MDI子窗体显示切换的实现过程

类似excel表格中各个表单sheet的切换效果&#xff0c;使用tabcontrol控件实现类似的功能。效果如下&#xff1a; 过程涉及父窗体MDIParent1、子窗体main、自定义基础功能类MdiChildBase。 基础功能类MdiChildBase继承自Form创建&#xff0c;定义了一个委托SetTabControlDelega…

apisix 本地开发环境部署

apisix 本地开发环境部署 本地开发环境部署可以采用 docker-compose 部署&#xff0c;配置文件如下 apisix 配置文件 apisix:node_listen: 9080 # APISIX 节点监听地址enable_ipv6: falsehttp:port: 9080 # APISIX HTTP 端口#https:# port: 9443 # APISIX HTTPS 端口# ssl…

《机器学习》K-means 聚类 原理、参数解析、案例实现

1. 引言 随着数据的快速增长和复杂性的不断提高,如何从大量数据中提取有用信息已成为数据科学和人工智能领域的核心挑战。聚类作为一种无监督学习方法,通过将数据分为若干组,使得同一组内的样本具有较高的相似性,而不同组之间的样本差异显著。这种方法被广泛应用于数据分析…

探索极速Python:Sanic框架的魔力

文章目录 探索极速Python&#xff1a;Sanic框架的魔力背景&#xff1a;为什么选择Sanic&#xff1f;Sanic是什么&#xff1f;如何安装Sanic&#xff1f;简单的库函数使用方法场景应用示例常见Bug及解决方案总结 探索极速Python&#xff1a;Sanic框架的魔力 背景&#xff1a;为什…

带你了解RS485通讯网关-天拓四方

在当今工业自动化和智能化的浪潮中&#xff0c;高效、可靠的数据通讯是确保系统运行顺畅的关键。RS485通讯网关作为工业通讯网络中的核心设备&#xff0c;承担着数据传输的重要任务。本文将从RS485通讯网关的技术背景、功能特性、应用场景以及选购要点等方面进行深入探讨&#…

【智能算法应用】基于融合改进A星-麻雀搜索算法求解六边形栅格地图路径规划

目录 1.算法原理2.结果展示3.参考文献4.代码获取 1.算法原理 【智能算法】麻雀搜索算法&#xff08;SSA&#xff09;原理及实现 六边形栅格地图 分析一下地图&#xff1a; 六边形栅格地图上移动可以看做6领域运动&#xff0c;偶数列与奇数列移动方式有所差异&#xff0c;将六…

[每周一更]-(第112期):WDL(Workflow Description Language)说明及使用示例

文章目录 什么是WDL&#xff1f;WDL的基本结构示例 WDL 文件示例任务&#xff1a;字符串反转示例工作流&#xff1a;字符串处理 WDL 文件详解任务&#xff08;Task&#xff09;工作流&#xff08;Workflow&#xff09; 运行示例总结报错参考 什么是WDL&#xff1f; WDL&#x…

Java图形用户界面之Applet设计

Applet设计 前言一、Applet的基本工作原理与使用局限Applet的基本工作原理代码示例 Java Applet 的使用局限Java沙箱安全机制原理 Applet的生命周期与运行方式 二、Applet类Applet类的层次结构常用方法生命周期方法显示方法多媒体支持方法其他方法 三、Applet和GUI基于AWT和Swi…