首页 > 编程语言 >【ChernoC++笔记】智能指针

【ChernoC++笔记】智能指针

时间:2023-07-14 18:35:37浏览次数:47  
标签:std Cherno C++ Entity shared unique ptr 指针

【44】【Cherno C++】【中字】C++的智能指针

智能指针(Smart pointers)是C++中的一种特殊类型,用于管理动态分配的内存资源。智能指针通过封装指针,并在适当的时机自动释放内存,从而避免内存泄漏和悬空指针等常见问题。

unique_ptr

❓为什么叫做unique ptr?

unique_ptr不能复制:

如果复制一个unique_ptr,那么将会有两个指针指向同一块内存,其中一个死了就会释放这块内存,此时另一个指针指向了已经被释放的内存。

▶️unique_ptr的使用

*使用智能指针需要#include <memory>

std::unique_ptr<Entity> entity(new Entity);

unique_ptr不支持下面这种隐式构造,因为它的构造函数为explicit,需要显示构造。

// 不存在从 "Entity *" 转换到 "std::unique_ptr<Entity, std::default_delete<Entity>>" 的适当构造函数
std::unique_ptr<Entity> entity = new Entity();

▶️使用std::make_unique保证安全

如果构造函数抛出异常,可能会得到一个空悬指针导致内存泄漏。

// C++14支持make_unique
std::unique_ptr<Entity> entity = std::make_unique<Entity>();

▶️作用域指针,超出作用域时,它就会被销毁

{   
	std::unique_ptr<Entity> entity(new Entity);
} // 离开作用域时,entity指针自动销毁

▶️不能复制unique_ptr

// 无法引用 函数 "std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp> &) [其中 _Tp=Entity, _Dp=std::default_delete<Entity>]" (已声明 所在行数:394,所属文件:"D:\\Programs\\mingw64\\lib\\gcc\\x86_64-w64-mingw32\\8.1.0\\include\\c++\\bits\\unique_ptr.h") -- 它是已删除的函数
std::unique_ptr<Entity> entity(new Entity);
std::unique_ptr<Entity> e0 = entity;

unique_ptr的定义中,删除了拷贝构造函数和拷贝构造符:

// Disable copy from lvalue.
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;

shared_ptr

▶️shared_ptr一般使用引用计数来实现

跟踪指针有多少个引用,当引用计数达到零,这块被指向的内存就被释放。

▶️使用std::make_shared提高效率

std::shared_ptr<Entity> sharedEntity(new Entity);

shared_ptr需要分配另一块内存(control block),用来存储引用计数。如果先创建一个new Entity,再传递给shared_ptr构造函数,必须做两次分配:先做一次new Entity的分配,然后是control block的分配。使用make_shared可以避免这一问题。

std::shared_ptr<Entity> sharedEntity = std::make_shared<Entity>();

▶️可以复制shared_ptr

std::shared_ptr<Entity> sharedEntity = std::make_shared<Entity>();
std::shared_ptr<Entity> e0 = sharedEntity;

▶️所有的shared_ptr死亡后,才会释放指向的内存

{
    std::shared_ptr<Entity> e0;
    {
        std::shared_ptr<Entity> sharedEntity = std::make_shared<Entity>();
        e0 = sharedEntity;
    } // 该作用域结束时,sharedEntity销毁,但Entity没有析构,因为e0仍持有对Entity的引用
} // 第二个作用域结束时,Entity才会析构

weak_ptr

和shared_ptr搭配使用。

weak_ptr在复制shared_ptr时,不会增加引用计数。

{
    std::shared_ptr<Entity> e0;
    {
        std::shared_ptr<Entity> sharedEntity = std::make_shared<Entity>();
		    std::weak_ptr<Entity> weakEntity = sharedEntity;
    } // 该作用域结束时,Entity就已经析构了
}

C++智能指针weak_ptr详解

weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。

借助 weak_ptr 类型指针可以获取 shared_ptr 指针的一些状态信息,比如有多少指向相同的 shared_ptr 指针、通过expired()判断shared_ptr指针指向的堆内存是否已经被释放等等,还可以解决shared_ptr 循环引用的问题。

什么情况下使用智能指针?

  • 当需要声明一个堆分配的对象,但不希望自己清理/不想显式地管理内存。
  • 尽量使用unique_ptr,因为它的开销较小。

标签:std,Cherno,C++,Entity,shared,unique,ptr,指针
From: https://www.cnblogs.com/rthete/p/17554728.html

相关文章

  • C++将WSAGetLastError转换成字符串信息
    #include<iostream>#include<Windows.h>#include<WinSock2.h>std::stringGetLastErrorMessage(){DWORDerrorCode=WSAGetLastError();LPSTRerrorMessage=nullptr;DWORDresult=FormatMessageA(FORMAT_MESSAGE_ALL......
  • 你需要知道关于C语言指针的一切
    EverythingyouneedtoknowaboutpointersinC你需要知道关于C语言指针的一切指针的定义指针是内存地址。(嗯,简短的段落。)开始假设你声明一个名为foo的变量。foo;这个变量占用一些内存。在当前主流的Intel处理器上,它占用四个字节的内存(因为int是四个字节宽)。现在......
  • c++学习之extern C
    g++也可以编译c语言函数,1//filename:extern_c.cc23#include<iostream>45#ifdef__cplusplus6extern"C"{7#endif8//c语言语句开始9#include<stdio.h>1011intcmain(){12printf("hello");13return0;14}1......
  • 文件位置指针
     istream 和 ostream 都提供了用于重新定位文件位置指针的成员函数。这些成员函数包括关于istream的 seekg("seekget")和关于ostream的 seekp("seekput")。seekg和seekp的参数通常是一个长整型。第二个参数可以用于指定查找方向。查找方向可以是 ios::beg(默认的,从流......
  • C++面试八股文:什么是构造函数?
    C++面试八股文:什么是构造函数?某日二师兄参加XXX科技公司的C++工程师开发岗位第29面:面试官:什么是构造函数?二师兄:构造函数是一种特殊的成员函数,用于创建和初始化类的对象。构造函数的名称与类的名称相同,并且没有返回类型。构造函数在对象被创建时自动调用。structFoo{F......
  • 指针
    指针在我的理解中,指针是用来存放地址的。指针也有大小,对于不同类型的指针char,short,int,,,double,它们的指针大小都是8个字节,对于64位机器是这样的,而对于32位机器它们的指针大小都为4个字节。我的是64位操作系统:#include<stdio.h>intmain(){ printf("%zd\n",sizeof(char*)); ......
  • c++ 段错误(核心已转储)
    一、什么是段错误?段错误应该就是访问了不可访问的内存,这个内存区要么是不存在的,要么是受到系统保护的,还有可能是缺少文件或者文件损坏。二、段错误产生的原因1、访问不存在的内存地址#include<iostream>#include<algorithm>#include<vector>#include<stdio.h>#include<st......
  • C++ 文件和流
     到目前为止,我们已经使用了 iostream 标准库,它提供了 cin 和 cout 方法分别用于从标准输入读取流和向标准输出写入流。本教程介绍如何从文件读取流和向文件写入流。这就需要用到C++中另一个标准库 fstream,它定义了三个新的数据类型:数据类型描述ofstream该数据类......
  • Java空指针异常优雅处理的方式
    1原因如下:由于Java开发过程中一不注意就会造成空指针异常,但是如果要避免这些空指针异常我们就可能需要写如下啰嗦有无聊的语句:if(test!=null&&test.size()>0){..............}为了避免写这些无聊的语句和避免NPE错误,我们可以用如下用法进行替代。......
  • C++ STL容器之vector、list
    (1)vector连续存储的容器,动态数组,在堆上分配空间底层实现:数组扩容机制:vector增加(插入)新元素时,如果未超过当时的容量,则还有剩余空间,那么直接添加到最后(插入指定位置),然后调整迭代器。如果没有剩余空间了,则会重新配置原有元素个数的两倍空间,然后将原空间元素通过复制的方式初始......