C++11特性:共享智能指针

在C++中没有垃圾回收机制,必须自己释放分配的内存,否则就会造成内存泄露。解决这个问题最有效的方法是使用智能指针(smart pointer)。智能指针是存储指向动态分配(堆)对象指针的类,用于生存期的控制,能够确保在离开指针所在作用域时,自动地销毁动态分配的对象,防止内存泄露。智能指针的核心实现技术是引用计数,每使用它一次,内部引用计数加1,每析构一次内部的引用计数减1,减为0时,删除所指向的堆内存。

C++11中提供了三种智能指针,使用这些智能指针时需要引用头文件<memory>

1. std::shared_ptr:共享的智能指针
2. std::unique_ptr:独占的智能指针
3. std::weak_ptr:弱引用的智能指针,它不共享指针,不能操作资源,是用来监视shared_ptr的。

弱引用的智能指针是辅助共享的智能指针的。

共享的智能指针独占的智能指针区别

假设new出来一块int类型的内存,使用共享的智能指针可以有多个共享的智能指针同时管理。

在每个智能指针的内部都有一个引用计数,记录的当前的这块内存被多少个智能指针共同管理着。

当这个智能指针被析构或者重置的时候,计数就会减一。注意在最后一个智能指针析构前,会把管理的内存一并析构掉。

由上述这个例子不难看出,共享智能指针可以多个指针同时管理,那么独占智能指针不允许多个指针同时管理一块内存。

后来的这个独占智能指针想要管理这块内存,就需要进行资源的转移,也就是使用move函数实现资源的转移,这样原来的独占智能指针就不能管理这块内存了。所以独占智能指针的计数永远为1

1. shared_ptr的初始化:

共享智能指针是指多个智能指针可以同时管理同一块有效的内存,共享智能指针shared_ptr 是一个模板类,如果要进行初始化有三种方式:通过构造函数std::make_shared辅助函数以及reset方法。共享智能指针对象初始化完毕之后就指向了要管理的那块堆内存,如果想要查看当前有多少个智能指针同时管理着这块内存可以使用共享智能指针提供的一个成员函数use_count,函数原型如下:

// 管理当前对象的 shared_ptr 实例数量,或若无被管理对象则为 0。
long use_count() const noexcept;

 1.1 通过构造函数初始化

// shared_ptr<T> 类模板中,提供了多种实用的构造函数, 语法格式如下:
std::shared_ptr<T> 智能指针名字(创建堆内存);

测试代码如下:

#include <iostream>
#include <memory>
using namespace std;int main()
{// 使用智能指针管理一块 int 型的堆内存shared_ptr<int> ptr1(new int(520));cout << "ptr1管理的内存引用计数: " << ptr1.use_count() << endl;// 使用智能指针管理一块字符数组对应的堆内存shared_ptr<char> ptr2(new char[12]);cout << "ptr2管理的内存引用计数: " << ptr2.use_count() << endl;// 创建智能指针对象, 不管理任何内存shared_ptr<int> ptr3;cout << "ptr3管理的内存引用计数: " << ptr3.use_count() << endl;// 创建智能指针对象, 初始化为空shared_ptr<int> ptr4(nullptr);cout << "ptr4管理的内存引用计数: " << ptr4.use_count() << endl;return 0;
}

测试代码输出的结果如下:

ptr1管理的内存引用计数: 1
ptr2管理的内存引用计数: 1
ptr3管理的内存引用计数: 0
ptr4管理的内存引用计数: 0

注意如果智能指针被初始化了一块有效内存,那么这块内存的引用计数+1,如果智能指针没有被初始化或者被初始化为nullptr空指针,引用计数不会+1。另外,不要使用一个原始指针初始化多个shared_ptr。

int *p = new int;
shared_ptr<int> p1(p);
shared_ptr<int> p2(p);		// error, 编译不会报错, 运行会出错

1.2 通过拷贝和移动构造函数初始化 

当一个智能指针被初始化之后,就可以通过这个智能指针初始化其他新对象。在创建新对象的时候,对应的拷贝构造函数或者移动构造函数就被自动调用了。

#include <iostream>
#include <memory>
using namespace std;int main()
{// 使用智能指针管理一块 int 型的堆内存, 内部引用计数为 1shared_ptr<int> ptr1(new int(520));cout << "ptr1管理的内存引用计数: " << ptr1.use_count() << endl;//调用拷贝构造函数shared_ptr<int> ptr2(ptr1);cout << "ptr2管理的内存引用计数: " << ptr2.use_count() << endl;shared_ptr<int> ptr3 = ptr1;cout << "ptr3管理的内存引用计数: " << ptr3.use_count() << endl;//调用移动构造函数shared_ptr<int> ptr4(std::move(ptr1));cout << "ptr4管理的内存引用计数: " << ptr4.use_count() << endl;std::shared_ptr<int> ptr5 = std::move(ptr2);cout << "ptr5管理的内存引用计数: " << ptr5.use_count() << endl;return 0;
}

测试程序输入的结果:

ptr1管理的内存引用计数: 1
ptr2管理的内存引用计数: 2
ptr3管理的内存引用计数: 3
ptr4管理的内存引用计数: 3
ptr5管理的内存引用计数: 3

通过拷贝构造函数的初始化: 

上述代码中的调用拷贝构造函数初始化,首先用ptr1来初始化ptr2,然后调用拷贝构造来初始化ptr3,这时候ptr2和ptr3都指向相同的一块内存,并且引用计数加一。 

 通过移动构造函数的初始化: 

 移动构造就需要右值引用了,右值引用就需要右值来进行初始化了。右值分为纯右值和将亡值,这里使用的是将亡值。使用move函数就可得到将亡值了。上述代码中通过转移的方式将ptr2的资源转移给了ptr5,引用计数并不能加一

1.3 通过std::make_shared初始化

通过C++提供的std::make_shared() 就可以完成内存对象的创建并将其初始化给智能指针,函数原型如下:

template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );

1. T:模板参数的数据类型 

 2.  Args&&... args :要初始化的数据,如果是通过make_shared创建对象,需按照构造函数的参数列表指定

通过make_shared就能创建一块普通类型的内存,也可以去创建某一个对象对应的内存


测试代码如下:

#include <iostream>
#include <string>
#include <memory>
using namespace std;class Test
{
public:Test() {cout << "construct Test..." << endl;}Test(int x) {cout << "construct Test, x = " << x << endl;}Test(string str) {cout << "construct Test, str = " << str << endl;}~Test(){cout << "destruct Test ..." << endl;}
};int main()
{// 使用智能指针管理一块 int 型的堆内存, 内部引用计数为 1shared_ptr<int> ptr1 = make_shared<int>(520);cout << "ptr1管理的内存引用计数: " << ptr1.use_count() << endl;shared_ptr<Test> ptr2 = make_shared<Test>();cout << "ptr2管理的内存引用计数: " << ptr2.use_count() << endl;shared_ptr<Test> ptr3 = make_shared<Test>(520);cout << "ptr3管理的内存引用计数: " << ptr3.use_count() << endl;shared_ptr<Test> ptr4 = make_shared<Test>("我是要成为海贼王的男人!!!");cout << "ptr4管理的内存引用计数: " << ptr4.use_count() << endl;return 0;
}

使用std::make_shared()模板函数可以完成内存地址的创建,并将最终得到的内存地址传递给共享智能指针对象管理。如果申请的内存是普通类型,通过函数的()可完成地址的初始化,如果要创建一个类对象,函数的()内部需要指定构造对象需要的参数,也就是类构造函数的参数。

1.4 通过 reset方法初始化

共享智能指针类提供的std::shared_ptr::reset方法函数原型如下:

void reset() noexcept;template< class Y >
void reset( Y* ptr );template< class Y, class Deleter >
void reset( Y* ptr, Deleter d );template< class Y, class Deleter, class Alloc >
void reset( Y* ptr, Deleter d, Alloc alloc );

1. ptr:指向要取得所有权的对象的指针
2. d:指向要取得所有权的对象的指针
3. aloc:内部存储所用的分配器 

测试代码如下:

#include <iostream>
#include <string>
#include <memory>
using namespace std;int main()
{// 使用智能指针管理一块 int 型的堆内存, 内部引用计数为 1shared_ptr<int> ptr1 = make_shared<int>(520);shared_ptr<int> ptr2 = ptr1;shared_ptr<int> ptr3 = ptr1;shared_ptr<int> ptr4 = ptr1;cout << "ptr1管理的内存引用计数: " << ptr1.use_count() << endl;cout << "ptr2管理的内存引用计数: " << ptr2.use_count() << endl;cout << "ptr3管理的内存引用计数: " << ptr3.use_count() << endl;cout << "ptr4管理的内存引用计数: " << ptr4.use_count() << endl;ptr4.reset();cout << "ptr1管理的内存引用计数: " << ptr1.use_count() << endl;cout << "ptr2管理的内存引用计数: " << ptr2.use_count() << endl;cout << "ptr3管理的内存引用计数: " << ptr3.use_count() << endl;cout << "ptr4管理的内存引用计数: " << ptr4.use_count() << endl;shared_ptr<int> ptr5;ptr5.reset(new int(250));cout << "ptr5管理的内存引用计数: " << ptr5.use_count() << endl;return 0;
}

测试代码输入的结果:

ptr1管理的内存引用计数: 4
ptr2管理的内存引用计数: 4
ptr3管理的内存引用计数: 4
ptr4管理的内存引用计数: 4ptr1管理的内存引用计数: 3
ptr2管理的内存引用计数: 3
ptr3管理的内存引用计数: 3
ptr4管理的内存引用计数: 0ptr5管理的内存引用计数: 1

对于一个未初始化的共享智能指针,可以通过reset方法来初始化,当智能指针中有值的时候,调用reset会使引用计数减1。

 简单来说reset有两个功能

1. 使指向某块内存的智能指针解除对这块内存的管理。

2. 让这个指针管理另外一块内存,相当于做了智能指针的重新初始化。

1.5 获取原始指针

通过智能指针可以管理一个普通变量或者对象的地址,此时原始地址就不可见了。当我们想要修改变量或者对象中的值的时候,就需要从智能指针对象中先取出数据的原始内存的地址再操作,解决方案是调用共享智能指针类提供的get()方法,其函数原型如下:

T* get() const noexcept;

当一个智能指针管理一块内存的时候,获取的原始指针是什么类型,这个T*返回的就是什么类型。 也就是智能指针管理的这块内存的类型

测试代码如下:

#include <iostream>
#include <string>
#include <memory>
using namespace std;int main()
{int len = 128;shared_ptr<char> ptr(new char[len]);// 得到指针的原始地址char* add = ptr.get();memset(add, 0, len);strcpy(add, "我是要成为海贼王的男人!!!");cout << "string: " << add << endl;shared_ptr<int> p(new int);*p = 100;cout << *p.get() << "  " << *p << endl;return 0;
}

 接下来通过一个示例程序来更加清楚的了解上述的前四个用法:

代码如下:

#include<iostream>
#include<memory>
using namespace std;class Test
{
public:Test(){cout << "construct Test..." << endl;}Test(int x) : m_num(x){cout << "construct Test,x = " << x << endl;}Test(string str){cout << "construct Test,str = " << str << endl;}~Test(){cout << "destruct Test..." << endl;}void setValue(int v){m_num = v;}void print(){cout << "m_num:" << m_num << endl;}private:int m_num;
};int main()
{// 通过构造函数初始化shared_ptr<int> ptr1(new int(3));cout << "ptr1 use_count:" << ptr1.use_count() << endl;// 移动构造和拷贝构造函数初始化// 移动构造:shared_ptr<int> ptr2 = move(ptr1);cout << "ptr1 use_count:" << ptr1.use_count() << endl;cout << "ptr2 use_count:" << ptr2.use_count() << endl;// 拷贝构造:// 需要一个实例对象来初始化,所以要使用ptr2来初始化// 因为ptr1的资源已经转移到ptr2中了shared_ptr<int> ptr3 = ptr2;cout << "ptr3 use_count:" << ptr3.use_count() << endl;cout << "ptr2 use_count:" << ptr2.use_count() << endl;// 通过std::make_shared初始化shared_ptr<int> ptr4 = make_shared<int>(8);// ()中的数就是给给new出来的这个int类型内存进行初始化shared_ptr<Test> ptr5 = make_shared<Test>(8);shared_ptr<Test> ptr6 = make_shared<Test>("luffy");// 通过reset初始化ptr6.reset();// 指针重置,引用计数变为0cout << "ptr6 use_count:" << ptr6.use_count() << endl;ptr5.reset(new Test("ace"));// 管理另一块内存cout << "ptr5 use_count:" << ptr5.use_count() << endl;// 获取原始指针return 0;
}

输出结果为:

ptr1 use_count:1
ptr1 use_count:0
ptr2 use_count:1
ptr3 use_count:2
ptr2 use_count:2
construct Test,x = 8
construct Test,str = luffy
destruct Test...
ptr6 use_count:0
construct Test,str = ace
destruct Test...
ptr5 use_count:1
destruct Test...

对输出结果进行分析:

当ptr1创建成功之后,他的引用计数就是1。然后通过移动拷贝构造函数转移ptr1的资源到ptr2,所以ptr1的引用计数变为0,ptr2的引用计数变为1。紧接着,ptr3进行的是一个拷贝构造,所以他的引用计数和ptr2一样为2,也就是说这块内存由ptr2和ptr3共同管理着。

ptr4和ptr5分别是整型和字符串类型,然后就是重置ptr6,ptr6管理的这个Test对象就被析构了,所以输出析构语句,引用计数也变为0。然后是让ptr5管理另一块内存,输出构造函数中的语句,所以ptr5之前管理的那块内存也析构了,输出析构语句。又因为ptr5管理着新的内存,所以引用计数仍然为1。最后,程序结束,ptr5管理的这块内存也析构了。

 那么怎么去使用这个初始化得到的共享智能指针呢?(有两种方式)

1. 通过智能指针取出原始地址:

// 获取原始指针
Test* t = ptr5.get();
t->setValue(1000);
t->print();

2.  通过智能指针对象直接进行操作 :

// 通过智能指针对象直接进行操作
// 将智能指针对象当作指针去使用
ptr5->setValue(999);
ptr5->print();

 2. 指定删除器

当智能指针管理的内存对应的引用计数变为0的时候,这块内存就会被智能指针析构掉了。另外,我们在初始化智能指针的时候也可以自己指定删除动作,这个删除操作对应的函数被称之为删除器,这个删除器函数本质是一个回调函数,我们只需要进行实现,其调用由智能指针完成的。

// 第二个参数是指定删除器,默认情况下可以不指定
// 删除器可以在外面创建一个或者写一个匿名函数(lambda表达式)
shared_ptr<Test> ppp(new Test(100), [](Test* t) {// 释放内存的操作 // 需要释放的是Test类型的指针// t指向的就是第一个参数cout << "----------------------" << endl;delete t;
});

输出结果为:

----------------------
destruct Test...
destruct Test...

由此可以看出这个删除器确定被调用了。

那么在什么时候必须要指定删除器函数呢?

 通过智能指针对象去管理一块数组内存的时候,如果不是数组内存,智能指针对象提供的默认删除器函数就能删除掉这块内存。如果管理的是一块数组内存就不能删除。

接下来用一段代码来演示:

#include<iostream>
#include<memory>
using namespace std;class Test
{
public:Test(){cout << "construct Test..." << endl;}Test(int x) : m_num(x){cout << "construct Test,x = " << x << endl;}Test(string str){cout << "construct Test,str = " << str << endl;}~Test(){cout << "destruct Test..." << endl;}void setValue(int v){m_num = v;}void print(){cout << "m_num:" << m_num << endl;}private:int m_num;
};int main()
{shared_ptr<Test> p1(new Test[5]);return 0;
}

输出结果为:

construct Test...
construct Test...
construct Test...
construct Test...
construct Test...
destruct Test...

由输出结果可以看出默认的删除器函数不能删除数组内存。

手动指定删除器:

shared_ptr<Test> p1(new Test[5], [](Test* t) {cout << "----------------------" << endl;delete[] t;
});

输出结果为:

construct Test...
construct Test...
construct Test...
construct Test...
construct Test...
----------------------
destruct Test...
destruct Test...
destruct Test...
destruct Test...
destruct Test...

在删除数组内存时,除了自己编写删除器,也可以使用C++提供的std::default_delete<T>()函数作为删除器,这个函数内部的删除功能也是通过调用delete来实现的,要释放什么类型的内存就将模板类型T指定为什么类型即可。具体处理代码如下:

int main()
{shared_ptr<Test> p2(new Test[5], default_delete<Test[]>());return 0;
}

注意:函数类型必须写[]不能写* 。而自己指定删除器中的参数类型可以也写成Test []t。

 输出结果和自己指定一样。

如果我们在程序中需要经常对数组类型的内存进行释放,我们可以去封装一个函数模板

代码如下:

#include <iostream>
#include <memory>
using namespace std;template <typename T>
shared_ptr<T> make_share_array(size_t size)
{// 返回匿名对象return shared_ptr<T>(new T[size], default_delete<T[]>());
}int main()
{shared_ptr<int> ptr1 = make_share_array<int>(10);cout << ptr1.use_count() << endl;shared_ptr<char> ptr2 = make_share_array<char>(128);cout << ptr2.use_count() << endl;return 0;
}

 本文参考:共享智能指针 | 爱编程的大丙 (subingwen.cn)

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

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

相关文章

机器学习 深度学习 神经网络

神经网络概念&#xff1a; 神经网络是一个由生物神经元组成的网络或电路&#xff0c;或者从现代意义上讲&#xff0c;是一个由人工神经元或节点组成的人工神经网络。因此&#xff0c;一个神经网络要么是由生物神经元组成的生物神经网络&#xff0c;要么是用于解决人工智能&…

35_36-Golang 中的 go mod 以及 Golang 包详解

**Golang **中的 **go mod **以及 **Golang **包详解 主讲教师&#xff1a;&#xff08;大地&#xff09; 合作网站&#xff1a;www.itying.com** **&#xff08;IT 营&#xff09; 我的专栏&#xff1a;https://www.itying.com/category-79-b0.html 一、Golang 中包的介绍和…

Ubuntu 常用命令之 chown 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 chown 命令在 Ubuntu 系统中用于改变文件或目录的所有者和组。这个命令的基本格式是 chown [选项]... [所有者][:[组]] 文件...。 chown 命令的主要参数有 -c 或 --changes&#xff1a;类似 verbose&#xff0c;但只在发生改变时…

【产品经理】Axure原型工具教程

笔记为项目总结笔记&#xff0c;若有错误欢迎指出哟~ Axure原型工具教程 Axure简介原型图分类常用操作常用原件常用交互母版常用设备分辨率 Axure简介 Axure是一款专业的原型设计与交互设计软件&#xff0c;可以帮助用户快速创建高保真的原型和交互设计。Axure支持多种常见的交…

【案例】图片预览

效果图 如何让图片放大&#xff0c;大多数的UI组件都带有这种功能&#xff0c;今天给大家介绍的这个插件除了放大之外&#xff0c;还可以旋转、移动、翻转、旋转、二次放大&#xff08;全屏&#xff09; 实现 npm i v-viewer -Smain.js 中引入 import viewerjs/dist/viewer.c…

【网络基础】网线制作集线器和交换机讲解路由设置

目录 一 网线制作 ● 由来 ● 材料&#xff08;4种&#xff09; ● 步骤 二 集线器和交换机 2.1 OSI七层模型概念 2.2 集线器与交换机简介 三 路由器设置 3.1 路由器概念 3.2 路由器设置管理登入 3.2.1 进路由器管理(新路由器) 3.2.2 进路由器管理(旧路由器) 四 全…

ROS笔记之rosbag的快速切片(C++实现)

ROS笔记之rosbag的快速切片(C实现) —— 杭州 2023-12-21 夜 code review 文章目录 ROS笔记之rosbag的快速切片(C实现)1.运行效果2.文件结构3.fast_rosbag_slice.cpp4.CMakeLists.txt5.package.xml6.对fast_rosbag_slice.cpp进行函数封装 正常该功能是ROS官方命令行&#xff1a…

C#合并多个Word文档(微软官方免费openxml接口)

g /// <summary>/// 合并多个word文档&#xff08;合并到第一文件&#xff09;/// </summary>/// <param name"as_word_paths">word文档完整路径</param>/// <param name"breakNewPage">true(默认值)&#xff0c;合并下一个…

华为路由配置值——通过流策略实现策略路由(重定向到不同的下一跳)

组网图形 图1 配置策略路由组网图 策略路由简介配置注意事项组网需求配置思路操作步骤配置文件 策略路由简介 传统的路由转发原理是首先根据报文的目的地址查找路由表&#xff0c;然后进行报文转发。但是目前越来越多的用户希望能够在传统路由转发的基础上根据自己定义的策略…

React-Native环境搭建(IOS)

系列文章目录 React-Native环境搭建&#xff08;IOS&#xff09; 目录 系列文章目录前言一、IOS环境搭建前置说明二、环境搭建步骤1.Homebrew安装2.安装Xcode3.Node4.watchman5.CocoaPods 三、项目启动1.初始化项目2.项目启动 总结 前言 React-Native开发环境的搭建&#xff…

【已解决】vs2015下c++对sqlite的操作

本博文源于笔者操作sqlite3&#xff0c;借鉴了很多文章的思路&#xff0c;这里并整理了c常用的对数据库的操作供大家点赞收藏以后备用。包含了&#xff1a;c对sqlite3的创建数据库、创建数据表、写入数据表、读取数据表、删除数据表。也包括了最基础的让c运行sqlite3.内容供读者…

手机无人直播的兴起

近年来&#xff0c;随着科技的不断进步和智能手机的普及&#xff0c;手机无人直播成为了一种新兴的传媒方式。手持手机&#xff0c;不经过镜头操作人员的干预&#xff0c;通过直播平台实时分享自己的所见所闻&#xff0c;成为了越来越多人的选择。手机无人直播的盛行离不开以下…

[node]Node.js 中REPL简单介绍

[node]Node.js 中REPL简单介绍 什么是REPL为什么使用REPL如何使用REPL 命令REPL模式node的全局内容展示node全局所有模块查看全局模块具体内容其它命令 实践 什么是REPL Node.js REPL(Read Eval Print Loop:交互式解释器) 表示电脑的环境&#xff0c;类似 Windows 系统的终端或…

Hardhat环境搭建(六)---无需翻墙

Hardhat环境搭建 官方地址 node环境 npm环境 git环境 安装hardhat npm init npminit是什么 在node开发中使用npm init会生成一个pakeage.json文件&#xff0c;这个文件主要是用来记录这个项目的详细信息的&#xff0c;它会将我们在项目开发中所要用到的包&#xff0c;以…

Mac查询本机ip地址

Mac系统版本和网络配置不同&#xff0c;可能会有一些细微差别。 一、 使用系统偏好设置 1、点击屏幕左上角的Apple图标&#xff0c;选择“系统偏好设置”。 2、点击“网络”。 3、 在左侧选择当前连接的网络&#xff08;如Wi-Fi或以太网&#xff09;&#xff0c;在右侧界面&a…

达梦到达梦的外部链接dblink(DM-DM DBLINK)

一. 使用场景&#xff1a; 部链接对象&#xff08;LINK&#xff09;是 DM 中的一种特殊的数据库实体对象&#xff0c;它记录了远程数据库的连接和路径信息&#xff0c;用于建立与远程数据的联系。通过多台数据库主库间的相互通讯&#xff0c;用户可以透明地操作远程数据库的数…

前端开发新趋势:Web3 与虚拟现实的技术融合

在当今互联网技术日新月异的时代&#xff0c;Web技术也在不断地发展和变革。从前端开发的角度来看&#xff0c;新技术的涌现和旧技术的迭代让前端开发者们面临着前所未有的挑战和机遇。Web3 与虚拟现实&#xff08;VR&#xff09;的技术融合&#xff0c;正是当前前端开发领域的…

​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化

2022年亚马逊云科技re:Invent盛会于近日在拉斯维加斯成功召开&#xff0c;吸引了众多业界精英和创新者。亚马逊云科技边缘服务副总裁Jan Hofmeyr在演讲中分享了关于亚马逊云科技海外服务器边缘计算的最新发展和创新成果&#xff0c;引发与会者热烈关注。 re:Invent的核心主题是…

九、W5100S/W5500+RP2040之MicroPython开发<HTTPOneNET示例>

文章目录 1. 前言2. 平台操作流程2.1 创建设备2.2 创建数据流模板 3. WIZnet以太网芯片4. 示例讲解以及使用4.1 程序流程图4.2 测试准备4.3 连接方式4.4 相关代码4.5 烧录验证 5. 注意事项6. 相关链接 1. 前言 在这个智能硬件和物联网时代&#xff0c;MicroPython和树莓派PICO正…

Kubernetes 的用法和解析 -- 7

k8s之共享存储pv&pvc 1 存储资源管理 在基于k8s容器云平台上&#xff0c;对存储资源的使用需求通常包括以下几方面&#xff1a; 1.应用配置文件、密钥的管理&#xff1b; 2.应用的数据持久化存储&#xff1b; 3.在不同的应用间共享数据存储&#xff1b; k8s的Volume抽象概…