C++之智能指针
前言
普通指针的不足
new和new门的内存需要用delete和delete[释放。
程序员的主观失误,忘了或漏了释放
程序员也不确定何时释放(例如多个线程共享同一个对象,没办法确定什么时候释放)
普通指针的释放
类内的指针,在析构函数中释放
C++内置数据类型,如何释放?
new出来的类,本身如何释放?
智能指针设计思路
智能指针是类模板,在栈上创建智能指针对象
把普通指针交给智能指针对象
智能指针对象过期时,调用析构函数释放普通指针的内存
什么是智能指针
智能指针是RALL机制对普通指针进行的一层封装。这样使得智能指针的行为动作像一个指针,本质上却是一个对象,这样可以方便管理一个对象的生命周期。
智能指针详解
unique_ptr
定义:unique_ptr独享它指向的对象,也就是说,同时只有一个unique_ptr指向同一个对象,当这个unique_ptr被销毁时,指向的对象也随即被销毁。
头文件:#include<memory>
template <typename T, typename D = default_delete<T>>
class unique_ptr
{
public:explicit unique_ptr(pointer p) noexcept; // 不可用于转换函数。~unique_ptr() noexcept; T& operator*() const; // 重载*操作符。T* operator->() const noexcept; // 重载->操作符。unique_ptr(const unique_ptr &) = delete; // 禁用拷贝构造函数。unique_ptr& operator=(const unique_ptr &) = delete; // 禁用赋值函数。unique_ptr(unique_ptr &&) noexcept; // 右值引用。unique_ptr& operator=(unique_ptr &&) noexcept; // 右值引用。// ...
private:pointer ptr; // 内置的指针。
};下面进行测试
#include<memory>
#include<iostream>
#include<vector>
using namespace std;
class AA
{
public:string m_name;AA() { cout << m_name << "调用构造函数AA()。" << endl;}AA(const string& name) : m_name(name) {cout << "调用构造函数AA(" << m_name << ")。" << endl;}~AA() { cout << "调用了析构函数~AA(" << m_name << ")。" << endl;}
};测试1
void test1()
{AA* p = new AA("张三");//delete p; //这里结社我们忘记delete
}运行结果:
调用构造函数AA(张三)。
我们发现出现了内存泄漏问题,这里我们是故意忘记释放,但是真正到了开发时,都有可能会忘记释放,那怎么办呢?我们可以用智能指针unique_ptr
测试2
void test2()
{AA* p = new AA("张三");unique_ptr<AA> p1(p);
}运行结果
调用构造函数AA(张三)。
张三调用了析构函数~AA(张三)。
我们惊奇的发现我们没有调用delete,但是也调用了析构函数,因为智能指针是一个类,它有析构函数,在析构函数中有delete语句。
并且类重载了->和*,可以像使用普通指针一样使用智能指针
测试3
void test3()
{AA* p = new AA("张三");unique_ptr<AA> p1(p);cout << (*p1).m_name << endl;cout << p1->m_name << endl;cout << p->m_name << endl;cout << (*p).m_name << endl;
}运行结果
调用构造函数AA(张三)。
张三
张三
张三
张三
张三调用了析构函数~AA(张三)。
基本用法
初始化
//方法1
unique_ptr<AA> p0(new AA("西施")); // 分配内存并初始化
//方法2
unique_ptr<AA> p0 = make_unique<AA>("西施"); // C++14标准。
unique_ptr<int> pp1=make_unique<int>(); // 数据类型为int。
unique_ptr<AA> pp2 = make_unique<AA>(); // 数据类型为AA,默认构造函数。
unique_ptr<AA> pp3 = make_unique<AA>("西施"); // 数据类型为AA,一个参数的构造函数。
unique_ptr<AA> pp4 = make_unique<AA>("西施",8); // 数据类型为AA,两个参数的构造函数。
//方法3
AA* p = new AA("西施");
unique_ptr<AA> p0(p); // 用已存在的地址初始化。注意:
重载了->和*,可以像使用普通指针一样使用unique_ptr
不支持普通的拷贝和赋值
explicit unique_ptr(pointer p) noexcept; // 因为有explicit,所以不可用于转换函数。
unique_ptr(const unique_ptr &) = delete; // 禁用拷贝构造函数
unique_ptr& operator=(const unique_ptr &) = delete; // 禁用赋值函数。
例如以下测试错误的
void test4()
{AA* p = new AA("张三");unique_ptr<AA> p1 = p; //错误,不能将普通指针直接复制给智能指针unique_ptr<AA>p2 = new AA("李四"); //错误,不能将普通指针直接复制给智能指针unique_ptr<AA> p3 = pu1; // 错误,不能用其它unique_ptr拷贝构造unique_ptr<AA> p4;p4=p1; //错误,不能用=对unique_ptr进行赋值
}为什么要禁用赋值函数呢?
这个与智能指针实现初衷有关,unique_ptr实现的是一个指针独享一份资源,如果可以复制的话,那个就会出现多个unique_ptr指针指向同一块资源,就会出现非法操作野指针。
不要用同一个裸指针初始化多个unique_ptr对象(也是出现非法操作野指针问题);
不要用unique_ptr管理不是new分配的内存;
get()方法返回裸指针;
用于函数的参数只能传引用;
不支持指针运算(+、-、++、--)。
技巧
1. 将一个unique_ptr赋给另一个时,如果原unique_ptr是一个临时右值,编译器允许这样做;如果源unique_ptr将存在一段时间,编译器禁止这样做。一般用于函数的返回值;
2. 用nullptr给unique_ptr赋值将释放对象,空的unique_ptr==nullptr;
3. release()释放对原始指针的控制权,将unique_ptr置为空,返回裸指针。(可用于把unique_ptr传递给子函数,子函数将负责释放对象);
4. std::move()可以转移对原始指针的控制权。(可用于把unique_ptr传递给子函数,子函数形参也是unique_ptr);
5. reset()释放对象;
6. swap()交换两个unique_ptr的控制权;
7. unique_ptr也可象普通指针那样,当指向一个类继承体系的基类对象时,也具有多态性质,如同使用裸指针管理基类对象和派生类对象那样;
8. unique_ptr不是绝对安全,如果程序中调用exit()退出,全局的unique_ptr可以自动释放,但局部的unique_ptr无法释放;
9. unique_ptr提供了支持数组的具体化版本。数组版本的unique_ptr,重载了操作符[],操作符[]返回的是引用,可以作为左值使用。
这里只演示第1、4、5、8、9;
示例 1:
unique_ptr<AA> func()
{unique_ptr<AA> pp(new AA("小谢"));return pp;
}
void test4()
{unique_ptr<AA> p1(new AA("张三"));unique_ptr<AA> p2;//p2 = p1;p2 = unique_ptr<AA>(new AA("李四"));cout << "调用func之前" << endl;p2 = func();cout << "调用func之后" << endl;
}
示例 4
void func(unique_ptr<AA> a)
{cout << a->m_name << endl;
}
void test5()
{unique_ptr<AA>pu(new AA("张三"));cout << "开始调用函数" << endl;func(move(pu));cout << "调用函数结束" << endl;
}这里函数调用时使用了move函数,将pu的管理权交给形参
示例 5
void reset(T * _ptr= (T *) nullptr);
pp.reset(); // 释放pp对象指向的资源对象。
pp.reset(nullptr); // 释放pp对象指向的资源对象
pp.reset(new AA("bbb")); // 释放pp指向的资源对象,同时指向新的对象。
示例 8
unique_ptr<AA> p(new AA("全局"));
int main()
{unique_ptr<AA> p1(new AA("局部"));exit(0);
}结果
调用构造函数AA(全局)。
调用构造函数AA(局部)。
全局调用了析构函数~AA(全局)。
示例 9
unique_ptr<int[]> parr1(new int[3]); // 不指定初始值。
unique_ptr<int[]> parr1(new int[3]{ 33,22,11 }); // 指定初始值。
cout << "parr1[0]=" << parr1[0] << endl;
cout << "parr1[1]=" << parr1[1] << endl;
cout << "parr1[2]=" << parr1[2] << endl;shared_ptr
定义:
shared_ptr共享它指向的对象,多个shared_ptr可以指向(关联)相同的对象,在内部采用计数机制来实现。
当新的shared_ptr与对象关联时,引用计数增加1。
当shared_ptr超出作用域时,引用计数减1。当引用计数变为0时,则表示没有任何shared_ptr与对象关联,则释放该对象。
基本用法
初始化
shared_ptr的构造函数也是explicit,但是,没有删除拷贝构造函数和赋值函数。
//方法一:
shared_ptr<AA> p0(new AA("西施")); // 分配内存并初始化。
//方法二:
shared_ptr<AA> p0 = make_shared<AA>("西施"); // C++11标准,效率更高。
shared_ptr<int> pp1=make_shared<int>(); // 数据类型为int。
shared_ptr<AA> pp2 = make_shared<AA>(); // 数据类型为AA,默认构造函数。
shared_ptr<AA> pp3 = make_shared<AA>("西施"); // 数据类型为AA,一个参数的构造函数。
shared_ptr<AA> pp4 = make_shared<AA>("西施",8); // 数据类型为AA,两个参数的构造函数。
//方法三:
AA* p = new AA("西施");
shared_ptr<AA> p0(p); // 用已存在的地址初始化。
//方法四:
shared_ptr<AA> p0(new AA("西施"));
shared_ptr<AA> p1(p0); // 用已存在的shared_ptr初始化,计数加1。
shared_ptr<AA> p1=p0; // 用已存在的shared_ptr初始化,计数加1注意:
智能指针重载了*和->操作符,可以像使用指针一样使用shared_ptr;
use_count()方法返回引用计数器的值;
unique()方法,如果use_count()为1,返回true,否则返回false
shared_ptr支持赋值,左值的shared_ptr的计数器将减1,右值shared_ptr的计算器将加1(当某个资源没有指向时就会被释放);
get()方法返回裸指针;
不要用同一个裸指针初始化多个shared_ptr;
不要用shared_ptr管理不是new分配的内存;
用于函数的参数只能传引用;
不支持指针运算(+、-、++、--)。
技巧
1. 用nullptr给shared_ptr赋值将把计数减1,如果计数为0,将释放对象,空shared_ptr==nullptr;
2. std::move()可以转移对原始指针的控制权。还可以将unique_ptr转移成shared_ptr;
3. reset()改变与资源的关联关系;
pp.reset(); // 解除与资源的关系,资源的引用计数减1。
pp. reset(new AA("bbb")); // 解除与资源的关系,资源的引用计数减1。关联新资源。
4. swap()交换两个shared_ptr的控制权;
void swap(shared_ptr<T> &_Right);
5. shared_ptr也可象普通指针那样,当指向一个类继承体系的基类对象时,也具有多态性质,如同使用裸指针管理基类对象和派生类对象那样;
6. shared_ptr不是绝对安全,如果程序中调用exit()退出,全局的shared_ptr可以自动释放,但局部的shared_ptr无法释放;
7. shared_ptr提供了支持数组的具体化版本;
数组版本的shared_ptr,重载了操作符[],操作符[]返回的是引用,可以作为左值使用;
8. shared_ptr的线程安全性:
shared_ptr的引用计数本身是线程安全(引用计数是原子操作)。
多个线程同时读同一个shared_ptr对象是线程安全的。
如果是多个线程对同一个shared_ptr对象进行读和写,则需要加锁。
多线程读写shared_ptr所指向的同一个对象,不管是相同的shared_ptr对象,还是不同的shared_ptr对象,也需要加锁保护。
9. 如果unique_ptr能解决问题,就不要用shared_ptr。unique_ptr的效率更高,占用的资源更少。
weak_ptr
定义
weak_ptr 是为了配合shared_ptr而引入的,它指向一个由shared_ptr管理的资源但不影响资源的生命周期。也就是说,将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。
不论是否有weak_ptr指向,如果最后一个指向资源的shared_ptr被销毁,资源就会被释放。
weak_ptr更像是shared_ptr的助手而不是智能指针
这里举个例子
#include <iostream>
#include <memory>
using namespace std;
class BB;
class AA
{
public:string m_name;AA() { cout << m_name << "调用构造函数AA()。\n"; }AA(const string& name) : m_name(name) { cout << "调用构造函数AA(" << m_name << ")。\n"; }~AA() { cout << "调用了析构函数~AA(" << m_name << ")。\n"; }shared_ptr<BB> m_p;
};
class BB
{
public:string m_name;BB() { cout << m_name << "调用构造函数BB()。\n"; }BB(const string& name) : m_name(name) { cout << "调用构造函数BB(" << m_name << ")。\n"; }~BB() { cout << "调用了析构函数~BB(" << m_name << ")。\n"; }shared_ptr<AA> m_p;
};
int main()
{shared_ptr<AA> pa = make_shared<AA>("西施a");shared_ptr<BB> pb = make_shared<BB>("西施b");pa->m_p = pb;pb->m_p = pa;
}程序结果:

显然AA和BB都没有析构,这是为什么呢??
AA中有类BB的指针指向pb,BB中有类AA的指针指向pa,所以pa和pb不知道谁先“死”,所以程序没办法判断谁先析构,最后干脆不析构了。
那怎么解决这个问题呢(智能指针的循环引用问题)?这里引出了weak_ptr指针,代码修改如下

基本用法
weak_ptr没有重载 ->和 *操作符,不能直接访问资源。
有以下成员函数:
1)operator=(); // 把shared_ptr或weak_ptr赋值给weak_ptr。
2)expired(); // 判断它指资源是否已过期(已经被销毁)。
3)lock(); // 返回shared_ptr,如果资源已过期,返回空的shared_ptr。
4)reset(); // 将当前weak_ptr指针置为空。
5)swap(); // 交换。
weak_ptr不控制对象的生命周期,但是,它知道对象是否还活着。
用lock()函数把它可以提升为shared_ptr,如果对象还活着,返回有效的shared_ptr,如果对象已经死了,提升会失败,返回一个空的shared_ptr。
提升的行为(lock())是线程安全的。
进行测试
int main()
{shared_ptr<AA> pa = make_shared<AA>("西施a");{shared_ptr<BB> pb = make_shared<BB>("西施b");pa->m_p = pb;pb->m_p = pa;shared_ptr<BB> pp = pa->m_p.lock(); // 把weak_ptr提升为shared_ptr。if (pp == nullptr)cout << "语句块内部:pa->m_p已过期。\n";elsecout << "语句块内部:pp->m_name=" << pp->m_name << endl;}shared_ptr<BB> pp = pa->m_p.lock(); // 把weak_ptr提升为shared_ptr。if (pp == nullptr)cout << "语句块外部:pa->m_p已过期。\n";elsecout << "语句块外部:pp->m_name=" << pp->m_name << endl;
}运行结果

删除器
#include <iostream>
#include <memory>
using namespace std;class AA
{
public:string m_name;AA() { cout << m_name << "调用构造函数AA()。" << endl; }AA(const string& name) : m_name(name) { cout << "调用构造函数AA(" << m_name << ")。" << endl; }~AA() { cout << "调用了析构函数~AA(" << m_name << ")。" << endl; }
};void deletefunc(AA* a) { // 删除器,普通函数。cout << "自定义删除器(全局函数)。" << endl;delete a;
}struct deleteclass // 删除器,仿函数。
{void operator()(AA* a) {cout << "自定义删除器(仿函数)。" << endl;delete a;}
};auto deleterlamb = [](AA* a) { // 删除器,Lambda表达式。cout << "自定义删除器(Lambda)。" << endl;delete a;
};int main()
{shared_ptr<AA> pa1(new AA("张三")); //不填,默认使用缺省//shared_ptr<AA> pa1(new AA("张三"), deletefunc);//shared_ptr<AA> pa2(new AA("李四"), deleteclass());//shared_ptr<AA> pa3(new AA("王五"), deleterlamb);//unique_ptr<AA,decltype(deletefunc)*> pu1(new AA("张三"), deletefunc);//unique_ptr<AA, void (*)(AA*)> pu0(new AA("李四"), deletefunc);//unique_ptr<AA, deleteclass> pu2(new AA("王五"), deleteclass());//unique_ptr<AA, decltype(deleterlamb)> pu3(new AA("小谢"), deleterlamb);return 0;
}
相关文章:
C++之智能指针
前言普通指针的不足new和new门的内存需要用delete和delete[释放。程序员的主观失误,忘了或漏了释放程序员也不确定何时释放(例如多个线程共享同一个对象,没办法确定什么时候释放)普通指针的释放类内的指针,在析构函数中…...
Redis实战-session共享之修改登录拦截器
在上一篇中Redis实战之session共享,我们知道了通过Redis实现session共享了,那么token怎么续命呢?怎么刷新用户呢?本来咱们就通过拦截器来实现这两个功能。 登录拦截器优化: 先来看看现在拦截器情况: 拦截…...
数据可视化,流程化处理pycharts-
本文直接进入可视化,输入讲解输入列表生成图片,关于pandas操作看这篇pandas matplotlib 导包后使用 import matplotlib.pyplot as plt饼图 使用 plt.figure 函数设置图片的大小为 15x15 使用 plt.pie 函数绘制饼图,并设置相关的参数&…...
1626_MIT 6.828 lab1课程大纲学习过程整理
全部学习汇总: GreyZhang/g_unix: some basic learning about unix operating system. (github.com) 现在lab1的内容全都学习完了,该做的练习也都做了。接下来,整理一下自己看这一部分课程讲义的一些笔记。 整理之前,先把自己完成…...
12月无情被辞:想给还不会自动化测试的技术人提个醒
公司前段时间缺人,也面了不少测试,结果竟没有一个合适的。一开始瞄准的就是中级的水准,也没指望来大牛,提供的薪资在10-20k,面试的人很多,但是平均水平很让人失望。基本能用一句话概括就是:3年测…...
开发必备技术--docker(使用篇)
文章目录前言Docker的基本概念概念数据卷虚拟网络镜像操作镜像名称镜像命令容器操作基本操作容器创建数据卷操作创建和查看数据卷其他指令实战前言 续接上一篇博文: 开发必备技术–docker(一) 这也是开学了,假期的最后一篇博文&a…...
2023备战金三银四,Python自动化软件测试面试宝典合集(三)
马上就又到了程序员们躁动不安,蠢蠢欲动的季节~这不,金三银四已然到了家门口,元宵节一过后台就有不少人问我:现在外边大厂面试都问啥想去大厂又怕面试挂面试应该怎么准备测试开发前景如何面试,一个程序员成长之路永恒绕…...
TortoiseGit 使用教程
一、下载工具 这里给大家准备了所有安装包自取 链接:https://pan.baidu.com/s/1xrxxgyNXNQEGD_RjwKnPMg 提取码:qwer 也可在官网自行下载最新版 1.下载git,直接去官网下载Git - Downloads,根据自己的系统合理下载,…...
Linux项目自动化构建工具make/Makefile
本文已收录至《Linux知识与编程》专栏! 作者:ARMCSKGT 演示环境:CentOS 7 目录 前言 正文 makefile文件与语法规则 make指令与执行逻辑 makefile任务刷新策略 .PHONY修饰为伪目标 最后 前言 会不会写makefile,从一个侧面…...
M100嵌入式自动吞吐式读写器|电动读卡机如何通过C#程序读取社保卡号
M100嵌入式自动吞吐式读写器|电动读卡机是一款双保护门功能读卡器,第一层防尘防异物机械门,第二层电动门。 M100嵌入式自动吞吐式读写器|电动读卡机采用耐高温、耐磨擦、高强度、抗老化的复合型塑胶为主体,在走卡通道两侧镶有不锈钢金属&…...
STM32----搭建Arduino开发环境
搭建Arduino开发环境前言一、Arduino软件1.软件下载2.软件安装3.软件操作二、Cortex官方内核三、烧录下载四、其他第三方内核1.Libmaple内核2.Steve改进的LibMaple 内核3.STMicroelectronics(ST)公司编写的内核总结前言 本章介绍搭建STM32搭建Arduino开发环境,包括…...
华为OD机试 - 事件推送(Python),真机试题
事件推送 题目 同一个数轴 X 上有两个点的集合 A={A1, A2, …, Am} 和 B={B1, B2, …, Bn}, Ai 和 Bj 均为正整数,A、B 已经按照从小到大排好序,A、B 均不为空, 给定一个距离 R (正整数), 列出同时满足如下条件的所有(Ai, Bj)数对: Ai <= BjAi, Bj 之间的距离小于…...
论如何获取CSDN原力
0x00 前言 因为个人需求,所以需要增长原力值,故对原力值的增长方式进行探索和总结。 0x01 正文 参考:https://blog.csdn.net/SoftwareTeacher/article/details/114499372 1.举报了劣质内容(博客,下载的资源&#x…...
流程引擎之发展史及对比总结
流程引擎渊源市场上比较有名的开源流程引擎有 jBPM、Activiti、Camunda、Flowable 和 Compileflow。其中 jBPM、Activiti、Flowable、camunda 四个框架同宗同源,祖先都是 jbpm4,开发者只要用过其中一个框架,基本上就会用其它三个。而 Compile…...
【DSView逻辑分析抓取波形CAN步骤-硬件连接-数据解析-底层波形认识CAN-工具使用】
【DSView逻辑分析抓取波形CAN步骤-硬件连接-数据解析-底层波形认识CAN】1、概述2、实验环境3、写在前面的一个问题4、实验准备(1)硬件连接1)CAN卡连接开发板(2)逻辑分析仪连接开发板(2) CAN卡连接软件&…...
C++中的模板
1.模板C 的模板一直是这门语言的一种特殊的艺术,模板甚至可以独立作为一门新的语言来进行使用。模板的哲学在于将一切能够在编译期处理的问题丢到编译期进行处理,仅在运行时处理那些最核心的动态服务,进而大幅优化运行期的性能。因此模板也被…...
Maven_第四章 使用Maven:IDEA环境
目录第一节 创建父工程第二节 配置Maven信息第三节 创建Java模块工程第四节 创建Web模块工程1、创建模块2、修改打包方式3、Web 设定4、借助IDEA生成web.xml5、设置 Web 资源的根目录6、测试6.1 创建文件6.2 配置tomcat第五节 其他操作1、在IDEA中执行Maven命令①直接执行②手动…...
RocketMQ基础学习
前言: RocketMQ阿里开源的,一款分布式的消息中间件,它经过阿里的生产环境的高并发、高吞吐的考验,同时,还支持分布式事务等场景。RocketMQ使用Java语言进行开发,方便Java开发者学习源码。但是,R…...
I.MX6ULL内核开发4:设备号的组成与哈希表
目录 一、设备号 二、hash table 一、设备号 文件夹:/home/geralt/linux_driver/kernel/ebf_linux_kernel_6ull_depth1/include/linux/kdev.h 这里面是linux中关于设备号的具体描述 #define MINORBITS 20 #define MINORMASK ((1U << MINORBITS) - 1)#defin…...
【博学谷学习记录】大数据课程-学习第六周总结
Hadoop 3.x的版本架构和模型介绍 由于Hadoop 2.0是基于JDK 1.7开发的,而JDK 1.7在2015年4月已停止更新,这直接迫使Hadoop社区基于JDK 1.8重新发布一个新的Hadoop版本,即hadoop 3.0。Hadoop 3.0中引入了一些重要的功能和优化,包括…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
