首页 > 编程知识 正文

哪款智能锁超c,头指针怎么创建

时间:2023-05-06 17:41:53 阅读:44286 作者:2256

参考资料: 《C++ Primer中文版 第五版》

除了静态内存和堆栈内存外,我们知道每个程序都有一个内存池,这部分内存被称为自由空间或堆。 程序使用堆来存储动态分配的对象,也就是在运行程序时分配的对象。 如果不再使用动态对象,则必须显式销毁代码。

在c中,动态内存管理是通过new-delete对进行的。 new:为动态内存中的对象分配空间,并返回指向该对象的指针。 delete :动态指向独占指针,销毁对象并释放相关内存。

在动态内存管理中,经常会出现两个问题。 一是忘记释放内存,引起内存泄漏。 一种情况是,如果指针还在引用存储器的情况下将其释放,则会产生引用不正确存储器的指针。

为了更容易(更安全)地使用动态内存,引入了智能指针的概念。 智能指针的行为类似于常规指针,但重要的区别在于它负责自动释放指向的对象。 标准库提供的两个智能指针的区别在于管理基本指针的方式不同。 在shared_ptr中,多个指针可以指向同一对象,而在unique_ptr中将指向的对象指定为“独占”。 标准库还定义了一个名为weak_ptr的附属类,它是对shared_ptr管理的对象的弱引用。 这三个智能指针在内存头文件中定义。

#shared_ptr类

创建智能指针时,必须输入其他信息。 指针可以指向以下类型:

shared_ptrstring p1; shared_ptrlistint p2; 初始化的智能指针中保存有空指针。

智能指针的使用方法与普通指针相似。 解析智能指针并返回其指向的对象,使用智能指针进行条件判断是检测是否为空。

if(P1P1-empty () ) *p1='hi ); 下表说明了shared_ptr和unique_ptr都支持的操作。

下表说明shared_ptr特定的作业。

make_shared函数:

最安全地分配和使用动态内存的方法是调用名为make_shared的标准库函数。 此函数将对象分配给动态内存并初始化,然后返回指向此对象的shared_ptr。 头文件与share_ptr一样,在memory中

必须指定要创建的对象的类型。 定义格式请参照以下示例。

shared _ ptr intp3=make _ shared int (42; shared _ ptr stringp4=make _ shared string (10,'9'; shared_ptrint p5=make_sharedint (; make_shared使用参数创建特定类型的对象。 如果不传递参数,对象将进行值初始化

复制和赋值shared_ptr

复制和赋值时,每个shared_ptr都会记录指向同一对象的其他shared_ptr的数量。

autop=make_sharedint(42; autoq(p; 每个shared_ptr都被认为具有与其相关联的计数器(通常称为引用计数),并且每次复制shared_ptr时都会递增计数器。 如果为shared_ptr提供新值或销毁shared_ptr (例如,本地shared_ptr脱离范围),则计数器递减,且shared_ptr的计数器

autor=make_sharedint(42; //r所指的int中只有一个引用者r=q; //r赋值,如果其他地址//增量q指向的对象的引用数//减量r指向的对象的引用数//r指向的对象中不再有引用者,则自动释放shared_ptr并管理对象

当指向对象的最后一个shared_ptr被销毁时,shared_ptr类将自动销毁对象。 这与构造函数类似,每个类都有一个析构函数,并被另一个特殊的成员资格函数丢弃。 析构函数控制对象被销毁时要做什么。 析构函数通常用于释放分配给对象的资源。 shared_ptr析构函数减少对其指向的对象的引用数。 当引用计数为0时,shared_ptr析构函数将销毁对象并释放正在使用的内存。

shared_ptr还会自动释放相关内存

当动态对象不再使用时,shared_ptr类会自动释放动态对象。 该功能使动态内存的使用变得非常容易。 请记住,如果将shared_ptr放在一个容器中,然后不需要所有元素,而只使用其中的一部分,请删除erase中不再需要的元素。

使用动态生存期的资源类:

程序使用动态内存的原因:

)1)程序不知道自己需要使用多少对象

)2)程序不知道所需对象的准确类型

)3)程序需要在多个对象之间共享数据

直接管理内存

c定义了两个运算符来分配和释放动态内存、new和delete,使用这两个运算符更容易出错。

使用new动态分配和初始化对象

在自由空间分配的

内存是无名的,因此new无法为其分配的对象命名,而是返回一个指向该对象的指针。

int *pi = new int;//pi指向一个动态分配的、未初始化的无名对象

此new表达式在自由空间构造一个int型对象,并返回指向该对象的指针

默认情况下,动态分配的对象是默认初始化的,这意味着内置类型或组合类型的对象的值将是未定义的,而类类型对象将用默认构造函数进行初始化。

string *ps = new string;//初始化为空stringint *pi = new int;//pi指向一个未初始化的int

我们可以直接使用直接初始化方式来初始化一个动态分配一个动态分配的对象。我们可以使用传统的构造方式,在新标准下,也可以使用列表初始化

int *pi = new int(1024);string *ps = new string(10,'9');vector<int> *pv = new vector<int>{0,1,2,3,4,5,6,7,8,9};

也可以对动态分配的对象进行初始化,只需在类型名之后跟一对空括号即可;

动态分配的const对象

const int *pci = new const int(1024);//分配并初始化一个const intconst string *pcs = new const string;//分配并默认初始化一个const的空string

类似其他任何const对象,一个动态分配的const对象必须进行初始化。对于一个定义了默认构造函数的类类型,其const动态对象可以隐式初始化,而其他类型的对象就必须显式初始化。由于分配的对象就必须显式初始化。由于分配的对象是const的,new返回的指针就是一个指向const的指针。

内存耗尽:
虽然现代计算机通常都配备大容量内村,但是自由空间被耗尽的情况还是有可能发生。一旦一个程序用光了它所有可用的空间,new表达式就会失败。默认情况下,如果new不能分配所需的内存空间,他会抛出一个bad_alloc的异常,我们可以改变使用new的方式来阻止它抛出异常

//如果分配失败,new返回一个空指针int *p1 = new int;//如果分配失败,new抛出std::bad_allocint *p2 = new (nothrow)int;//如果分配失败,new返回一个空指针

我们称这种形式的new为定位new,定位new表达式允许我们向new传递额外的参数,在例子中我们传给它一个由标准库定义的nothrow的对象,如果将nothrow传递给new,我们的意图是告诉它不要抛出异常。如果这种形式的new不能分配所需内存,它会返回一个空指针。bad_alloc和nothrow都在头文件new中。

释放动态内存
为了防止内存耗尽,在动态内存使用完之后,必须将其归还给系统,使用delete归还。

指针值和delete
我们传递给delete的指针必须指向动态内存,或者是一个空指针。释放一块并非new分配的内存或者将相同的指针释放多次,其行为是未定义的。即使delete后面跟的是指向静态分配的对象或者已经释放的空间,编译还是能够通过,实际上是错误的。

动态对象的生存周期直到被释放时为止
由shared_ptr管理的内存在最后一个shared_ptr销毁时会被自动释放,但是通过内置指针类型来管理的内存就不是这样了,内置类型指针管理的动态对象,直到被显式释放之前都是存在的,所以调用这必须记得释放内存。

使用new和delete管理动态内存常出现的问题:
(1)忘记delete内存
(2)使用已经释放的对象
(3)同一块内存释放两次

delete之后重置指针值
在delete之后,指针就变成了空悬指针,即指向一块曾经保存数据对象但现在已经无效的内存的地址

有一种方法可以避免悬空指针的问题:在指针即将要离开其作用于之前释放掉它所关联的内存
如果我们需要保留指针可以在delete之后将nullptr赋予指针,这样就清楚的指出指针不指向任何对象。
动态内存的一个基本问题是可能多个指针指向相同的内存

shared_ptr和new结合使用
如果我们不初始化一个智能指针,它就会被初始化成一个空指针,接受指针参数的职能指针是explicit的,因此我们不能将一个内置指针隐式转换为一个智能指针,必须直接初始化形式来初始化一个智能指针

shared_ptr<int> p1 = new int(1024);//错误:必须使用直接初始化形式shared_ptr<int> p2(new int(1024));//正确:使用了直接初始化形式

下表为定义和改变shared_ptr的其他方法:

不要混合使用普通指针和智能指针
如果混合使用的话,智能指针自动释放之后,普通指针有时就会变成悬空指针,当将一个shared_ptr绑定到一个普通指针时,我们就将内存的管理责任交给了这个shared_ptr。一旦这样做了,我们就不应该再使用内置指针来访问shared_ptr所指向的内存了。
也不要使用get初始化另一个智能指针或为智能指针赋值

shared_ptr<int> p(new int(42));//引用计数为1int *q = p.get();//正确:但使用q时要注意,不要让它管理的指针被释放{//新程序块//未定义:两个独立的share_ptr指向相同的内存shared_ptr(q);}//程序块结束,q被销毁,它指向的内存被释放int foo = *p;//未定义,p指向的内存已经被释放了

p和q指向相同的一块内部才能,由于是相互独立创建,因此各自的引用计数都是1,当q所在的程序块结束时,q被销毁,这会导致q指向的内存被释放,p这时候就变成一个空悬指针,再次使用时,将发生未定义的行为,当p被销毁时,这块空间会被二次delete

其他shared_ptr操作
可以使用reset来将一个新的指针赋予一个shared_ptr:

p = new int(1024);//错误:不能将一个指针赋予shared_ptrp.reset(new int(1024));//正确。p指向一个新对象

与赋值类似,reset会更新引用计数,如果需要的话,会释放p的对象。reset成员经常和unique一起使用,来控制多个shared_ptr共享的对象。在改变底层对象之前,我们检查自己是否是当前对象仅有的用户。如果不是,在改变之前要制作一份新的拷贝:

if(!p.unique())p.reset(new string(*p));//我们不是唯一用户,分配新的拷贝*p+=newVal;//现在我们知道自己是唯一的用户,可以改变对象的值

智能指针和异常
如果使用智能指针,即使程序块过早结束,智能指针也能确保在内存不再需要时将其释放,sp是一个shared_ptr,因此sp销毁时会检测引用计数,当发生异常时,我们直接管理的内存是不会自动释放的。如果使用内置指针管理内存,且在new之后在对应的delete之前发生了异常,则内存不会被释放。

使用我们自己的释放操作
默认情况下,shared_ptr假定他们指向的是动态内存,因此当一个shared_ptr被销毁时,会自动执行delete操作,为了用shared_ptr来管理一个connection,我们必须首先必须定义一个函数来代替delete。这个删除器函数必须能够完成对shared_ptr中保存的指针进行释放的操作。

智能指针陷阱:
(1)不使用相同的内置指针值初始化(或reset)多个智能指针。
(2)不delete get()返回的指针
(3)不使用get()初始化或reset另一个智能指针
(4)如果你使用get()返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变为无效了
(5)如果你使用智能指针管理的资源不是new分配的内存,记住传递给它一个删除器
#unique_ptr
某个时刻只能有一个unique_ptr指向一个给定对象,由于一个unique_ptr拥有它指向的对象,因此unique_ptr不支持普通的拷贝或赋值操作。
下表是unique的操作:

虽然我们不能拷贝或者赋值unique_ptr,但是可以通过调用release或reset将指针所有权从一个(非const)unique_ptr转移给另一个unique

//将所有权从p1(指向string Stegosaurus)转移给p2unique_ptr<string> p2(p1.release());//release将p1置为空unique_ptr<string>p3(new string("Trex"));//将所有权从p3转移到p2p2.reset(p3.release());//reset释放了p2原来指向的内存

release成员返回unique_ptr当前保存的指针并将其置为空。因此,p2被初始化为p1原来保存的指针,而p1被置为空。
reset成员接受一个可选的指针参数,令unique_ptr重新指向给定的指针。
调用release会切断unique_ptr和它原来管理的的对象间的联系。release返回的指针通常被用来初始化另一个智能指针或给另一个智能指针赋值。
不能拷贝unique_ptr有一个例外:我们可以拷贝或赋值一个将要被销毁的unique_ptr.最常见的例子是从函数返回一个unique_ptr.

unique_ptr<int> clone(int p){//正确:从int*创建一个unique_ptr<int>return unique_ptr<int>(new int(p));}

还可以返回一个局部对象的拷贝:

unique_ptr<int> clone(int p){unique_ptr<int> ret(new int(p));return ret;}

向后兼容:auto_ptr
标准库的较早版本包含了一个名为auto_ptr的类,它具有uniqued_ptr的部分特性,但不是全部。
用unique_ptr传递删除器
unique_ptr默认使用delete释放它指向的对象,我们可以重载一个unique_ptr中默认的删除器
我们必须在尖括号中unique_ptr指向类型之后提供删除器类型。在创建或reset一个这种unique_ptr类型的对象时,必须提供一个指定类型的可调用对象删除器。

#weak_ptr
weak_ptr是一种不控制所指向对象生存期的智能指针,它指向一个由shared_ptr管理的对象,将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放,即使有weak_ptr指向对象,对象还是会被释放。
weak_ptr的操作

由于对象可能不存在,我们不能使用weak_ptr直接访问对象,而必须调用lock,此函数检查weak_ptr指向的对象是否存在。如果存在,lock返回一个指向共享对象的shared_ptr,如果不存在,lock将返回一个空指针

#scoped_ptr
scoped和weak_ptr的区别就是,给出了拷贝和赋值操作的声明并没有给出具体实现,并且将这两个操作定义成私有的,这样就保证scoped_ptr不能使用拷贝来构造新的对象也不能执行赋值操作,更加安全,但有了"++""–"以及“*”“->”这些操作,比weak_ptr能实现更多功能。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。