C++初阶(八)--内存管理
目录
引入:
一、C++中的内存布局
1.内存区域
2.示例变量存储位置说明
二、C语言中动态内存管理
三、C++内存管理方式
1.new/delete操作内置类型
2.new和delete操作自定义类型
四、operator new与operator delete函数(重要点进行讲解)
五、new和delete的实现原理
六、定位 new 和定位 delete
七、面试题
1.malloc/free和new/delete的区别?
2.内存泄漏
引入:
以下代码分别存储在哪个区域
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{static int staticVar = 1;int localVar = 1;int num1[10] = { 1, 2, 3, 4 };char char2[] = "abcd";char* pChar3 = "abcd";int* ptr1 = (int*)malloc(sizeof (int)* 4);int* ptr2 = (int*)calloc(4, sizeof(int));int* ptr3 = (int*)realloc(ptr2, sizeof(int)* 4);free(ptr1);free(ptr3);
}
图解:
一、C++中的内存布局
在了解具体的内存管理操作之前,先得清楚 C++ 程序的内存布局。一般来说,一个 C++ 程序的内存可以大致分为以下几个区域:
1.内存区域
-
内核空间:
- 用户代码不能读写。
- 操作系统内核运行在此空间,负责管理系统资源和执行关键任务。
-
代码区(Text Segment):
- 存放程序的可执行代码,即机器指令。
- 通常是只读的,防止程序在运行过程中意外修改自身的代码。
-
全局 / 静态存储区(Data Segment):
- 存储全局变量和静态变量。
- 全局变量在整个程序的生命周期内都存在,而静态变量(包括局部静态变量)根据其定义的作用域有不同的可见性,但它们的生命周期都是从程序开始到结束。
-
栈区(Stack):
- 用于存储函数调用时的局部变量、函数参数以及返回地址等信息。
- 遵循后进先出(LIFO)的原则,每当一个函数被调用时,相关的信息就会被压入栈中,函数执行完毕后,这些信息又会被弹出栈。
- 栈的大小通常是在程序启动时就确定好的,相对有限,如果在栈上分配过多的内存,可能会导致栈溢出的错误。
-
堆区(Heap):
- 是一块相对较大且比较灵活的内存区域,用于动态分配内存。
- 程序员可以在程序运行期间根据需要随时在堆上申请和释放内存。
- 与栈不同,堆上的内存分配和释放需要程序员手动进行管理,这也正是内存管理容易出现问题的地方之一。如果忘记释放堆内存,会导致内存泄漏。
-
常量存储区:
- 存放常量数据,如字符串常量等。
- 这些数据在程序运行期间不能被修改。
-
内存映射段:
- 可以用于文件映射、动态库加载、匿名映射等。
- 提供了一种将文件或其他资源映射到进程内存空间的方式,以便更高效地访问这些资源。
2.示例变量存储位置说明
1、globalVar在哪里?
根据上面的代码可知,glovalVar是在main函数外创建的变量,即在全局创建的变量,全局变量存放在数据段(静态区)中。
2、staticGlobalVar在哪里?
staticGlobalVar是在main函数外创建的静态变量,即在全局创建的静态变量,全局静态变量存放在数据段(静态区)中。
3、staticVar在哪里?staticVar是在main函数内部创建的静态变量,即在局部创建的静态变量,局部静态变量存放在数据段(静态区)中。
4、localVar在哪里?
localVar是在main函数内部创建的变量,即在局部创建的普通变量,局部创建的普通变量存放在栈区。
5、char2在哪里?char2是在main函数内部创建的数组的数组名,即在局部创建的多个普通变量,局部创建的普通变量存放在栈区。
6、* char2在哪里?
*char2是对数组的的首元素进行解引用,解引用的值存放在哪个区域,*char2的则存放在哪个区域,*char2是数组的第一个字符,即字符变量中的第一个元素,字符变量存放在栈区,因此*char2存放在栈区。
7、pChar3在哪里?pChar3是在main函数内部创建的const修饰的常指针变量,实质还是一个局部创建的变量,只是该变量的值不能修改,因此pChar3存放在栈区。
8、* pChar3在哪里?
*pChar3是对数组的的首元素进行解引用,解引用的值存放在哪个区域,*pChar3的则存放在哪个区域,*pChar3是常量字符串的第一个字符,字符常量存放在代码段(常量区),因此*pChar3存放在代码段(常量区)。
9、ptr1在哪里?ptr1是在main函数内部创建的指针变量,实质还是一个局部创建的变量,因此pChar3存放在栈区。(ptr2、ptr3同理)
10、* ptr1在哪里?
*ptr1是对数组的的首元素进行解引用,解引用的值存放在哪个区域,*ptr1的则存放在哪个区域,*ptr1是通过动态开辟的空间,动态开辟的空间存放在堆区,因此*ptr1存放在堆区。(ptr2、ptr3同理)
顺便提一下:为什么说栈是向下增长的,而堆是向上增长的?
简单来说,在一般情况下,在栈区开辟空间,先开辟的空间地址较高,而在堆区开辟空间,先开辟的空间地址较低。
例如,下面代码中,变量a和变量b存储在栈区,指针c和指针d指向堆区的内存空间:
#include <iostream>
using namespace std;
int main()
{//栈区开辟空间,先开辟的空间地址高int a = 10;int b = 20;cout << &a << endl;cout << &b << endl;//堆区开辟空间,先开辟的空间地址低int* c = (int*)malloc(sizeof(int)* 10);int* d = (int*)malloc(sizeof(int)* 10);cout << c << endl;cout << d << endl;return 0;
}
因为在栈区开辟空间,先开辟的空间地址较高,所以打印出来a的地址大于b的地址;在堆区开辟空间,先开辟的空间地址较低,所以c指向的空间地址小于d指向的空间地址。
注意:在堆区开辟空间,后开辟的空间地址不一定比先开辟的空间地址高。因为在堆区,后开辟的空间也有可能位于前面某一被释放的空间位置。
二、C语言中动态内存管理
1.malloc:
malloc函数的功能是开辟指定字节大小的内存空间,如果开辟成功就返回该空间的首地址,如果开辟失败就返回一个NULL。传参时只需传入需要开辟的字节个数。
2.calloc
calloc函数的功能也是开辟指定大小的内存空间,如果开辟成功就返回该空间的首地址,如果开辟失败就返回一个NULL。calloc函数传参时需要传入开辟的内存用于存放的元素个数和每个元素的大小。calloc函数开辟好内存后会将空间内容中的每一个字节都初始化为0。
3.realloc
realloc函数可以调整已经开辟好的动态内存的大小,第一个参数是需要调整大小的动态内存的首地址,第二个参数是动态内存调整后的新大小。realloc函数与上面两个函数一样,如果开辟成功便返回开辟好的内存的首地址,开辟失败则返回NULL。
4.free
free函数的作用就是将malloc、calloc以及realloc函数申请的动态内存空间释放,其释放空间的大小取决于之前申请的内存空间的大小。
这里只做简单的概述,若还想进一步了解malloc、calloc、realloc和free,请阅读动态内存管理。
三、C++内存管理方式
C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因 此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。
1.new/delete操作内置类型
// 动态申请一个int类型的空间
int* ptr4 = new int;
// 动态申请一个int类型的空间并初始化为10
int* ptr5 = new int(10);
// 动态申请10个int类型的空间
int* ptr6 = new int[3];
//动态申请10个int类型的空间并初始化为0到9
int* p7 = new int[10] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; //申请 + 赋值delete ptr4;//销毁
delete ptr5;
delete[] ptr6;
delete[] p7;
注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用 new[]和delete[],注意:匹配起来使用。
2.new和delete操作自定义类型
对于以下自定义类型:
class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}private:int _a;
};int main()
{// 动态申请单个类的空间A* ptr4 = new A;// 动态申请一个A类的空间并初始化为10A* ptr5 = new A(10);// 动态申请10个A类的空间,创建 10 个对象A* ptr6 = new A[10];//动态申请10个A类的空间并初始化0到9A* ptr7 = new A[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; //申请 + 赋值delete ptr4;//销毁delete ptr5;delete[] ptr6;delete[] ptr7;}
给一个malloc版本
int main()
{// 动态申请单个类的空间A* ptr4 = (A*)malloc(sizeof(A));// 动态申请一个 A 类的空间并初始化为 10A* ptr5 = (A*)malloc(sizeof(A));// 动态申请 10 个 A 类的空间A* ptr6 = (A*)malloc(sizeof(A) * 10);// 动态申请 10 个 A 类的空间并初始化 0 到 9A* ptr7 = (A*)malloc(sizeof(A) * 10);free(ptr4);free(ptr5);free(ptr6);free(ptr7);return 0;
}
可以自己进行调试一下,会发现malloc,free和new,delete的区别。
注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc和free不会。
总结一下:
1、C++中如果是申请内置类型的对象或是数组,用new/delete和malloc/free没有什么区别。
2、如果是自定义类型,区别很大,new和delete分别是开空间+构造函数、析构函数+释放空间,而malloc和free仅仅是开空间和释放空间。
3、建议在C++中无论是内置类型还是自定义类型的申请和释放,尽量都使用new和delete。
四、operator new与operator delete函数(重要点进行讲解)
new和delete在底层上就是调用operator new
和operator delete的。
operator new
和operator delete
是 C++ 中用于动态内存分配和释放的操作符函数。它们可以被重载以实现自定义的内存分配策略。默认情况下,operator new
会调用底层的操作系统函数来分配内存,而operator delete
会释放由operator new
分配的内存。
operator new和operator delete的用法和malloc和free的用法完全一样,其功能都是在堆上申请和释放空间。
int* p1 = (int*)operator new(sizeof(int)* 10); //申请operator delete(p1); //销毁//-------------等价-----------------//int* p2 = (int*)malloc(sizeof(int)* 10); //申请free(p2); //销毁
默认行为:在 C++ 中,当我们使用new
关键字来分配内存时,实际上会调用operator new
函数。这个函数会尝试从堆中分配足够的内存来满足请求。如果分配成功,它会返回一个指向分配的内存的指针;如果分配失败,它会抛出一个std::bad_alloc
异常。
实际上,operator new的底层是通过调用malloc函数来申请空间的,当malloc申请空间成功时直接返回;若申请空间失败,则尝试执行空间不足的应对措施,如果该应对措施用户设置了,则继续申请,否则抛异常。而operator delete的底层是通过调用free函数来释放空间的。
注意:虽然说operator new和operator delete是系统提供的全局函数,但是我们也可以针对某个类,重载其专属的operator new和operator delete函数,进而提高效率。
例如,我们可以实现一个简单的内存池来提高内存分配的效率。
以下是一个简单的示例:
class MyClass
{
public:static void* operator new(size_t size){cout << "Custom operator new called." << endl;return malloc(size);}static void operator delete(void* ptr){cout << "Custom operator delete called." << endl;free(ptr);}
};int main()
{MyClass* obj = new MyClass();delete obj;return 0;
}
在这里,我们重载了MyClass
类的operator new
和operator delete
函数。当我们创建一个MyClass
对象时,会调用自定义的operator new
函数,该函数使用malloc
来分配内存。当我们释放一个MyClass
对象时,会调用自定义的operator delete
函数,该函数使用free
来释放内存。
五、new和delete的实现原理
内置类型
如果申请的是内置类型的空间,new/delete和malloc/free基本类似,不同的是,new/delete申请释放的是单个元素的空间,new[ ]/delete [ ]申请释放的是连续的空间,此外,malloc申请失败会返回NULL,而new申请失败会抛异常。
自定义类型
new的原理
1、调用operator new函数申请空间。
2、在申请的空间上执行构造函数,完成对象的构造。
delete的原理
1、在空间上执行析构函数,完成对象中资源的清理工作。
2、调用operator delete函数释放对象的空间。
new T[N]的原理
1、调用operator new[ ]函数,在operator new[ ]函数中实际调用operator new函数完成N个对象空间的申请。
2、在申请的空间上执行N次构造函数。
delete[ ] 的原理
1、在空间上执行N次析构函数,完成N个对象中资源的清理。
2、调用operator delete[ ]函数,在operator delete[ ]函数中实际调用operator delete函数完成N个对象空间的释放。
六、定位 new 和定位 delete
除了普通的operator new
和operator delete
,C++ 还提供了定位new
和定位delete
。定位new
允许我们在已经分配的内存上构造对象,而定位delete
允许我们在已经构造的对象上显式地调用析构函数并释放内存。
定位new
(placement new)
定位new
允许在已经分配好的内存地址上构造对象,而不是像普通的new
操作符那样从堆上动态分配新的内存。它的语法形式是new (place_address) type或者
或new(place_address)type(initializer-list),其中place_address
是一个已经分配好的内存地址,type
是要构造的对象类型,initializer-list是类型的初始化列表
定位delete
(placement delete)
定位delete
通常与定位new
配合使用,它允许在已经构造的对象上显式地调用析构函数并释放内存。一般情况下,不需要显式调用定位delete
,只有在特定的情况下(比如异常处理中需要确保正确的析构函数调用)才可能会用到。
使用场景:
定位new表达式在实际中一般是配合内存池使用,因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,就需要使用定位new表达式进行显示调用构造函数进行初始化。
#include <iostream>
#include <new>class MyClass
{
public:MyClass(){std::cout << "MyClass constructor called." << std::endl;}~MyClass(){std::cout << "MyClass destructor called." << std::endl;}
};int main()
{//此时只是开辟空间,没有创建对象,因为构造函数没有调用char* buffer = new char[sizeof(MyClass)];MyClass* obj = new (buffer) MyClass(); //new(place_address)type 形式obj->~MyClass();delete[] buffer;return 0;
}
代码讲解:
在这个例子中,首先分配了一块足够大的内存空间(通过char* buffer = new char[sizeof(MyClass)];
),然后使用定位new
在这个已经分配好的内存地址buffer
上构造了一个MyClass
对象。这里先显式调用对象的析构函数(obj->~MyClass();
),然后释放分配的内存块(delete[] buffer
)。注意,这里并没有直接使用定位delete
,而是通过先调用析构函数再释放内存块的方式来模拟定位delete
的行为。
总的来说,定位new
和定位delete
提供了一种在特定内存位置上构造和销毁对象的机制,在一些特定的场景下可以提供更灵活的内存管理方式。但使用时需要非常小心,确保内存的正确分配和释放,以避免出现内存泄漏和未定义行为等问题。
七、面试题
1.malloc/free和new/delete的区别?
共同点:
都是从堆上申请空间,并且需要用户手动释放。
不同点:
1、malloc和free是函数,new和delete是操作符。
2、malloc申请的空间不会初始化,new申请的空间会初始化。
3、malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即 可。
4、malloc的返回值是void*,在使用时必须强转,new不需要,因为new后跟的是空间的类 型。
5、malloc申请失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要 捕获异常。
6、申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数和析构函数,而 new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函 数完成空间中资源的清理。
2.内存泄漏
什么是内存泄漏,内存泄漏的危害?
内存泄漏:
内存泄漏是指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
内存泄漏的危害:
长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。
void MemoryLeaks()
{// 1.内存申请了忘记释放int* p1 = (int*)malloc(sizeof(int));int* p2 = new int;// 2.异常安全问题int* p3 = new int[10];Func(); // 这里Func函数抛异常导致 delete[] p3未执行,p3没被释放.delete[] p3;
}
内存泄漏分类
在C/C++中我们一般关心两种方面的内存泄漏:
1、堆内存泄漏(Heap Leak)
堆内存指的是程序执行中通过malloc、calloc、realloc、new等从堆中分配的一块内存,用完后必须通过调用相应的free或者delete释放。假设程序的设计错误导致这部分内容没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap
Leak。
2、系统资源泄漏
指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。
如何避免内存泄漏?
1、工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记住匹配的去释放。
2、采用RAII思想或者智能指针来管理资源。
3、有些公司内部规范使用内部实现的私有内存管理库,该库自带内存泄漏检测的功能选项。
4、出问题了使用内存泄漏工具检测。
内存泄漏非常常见,解决方案分为两种:
1、事前预防型。如智能指针等。
2、事后查错型。如泄漏检测工具。
相关文章:

C++初阶(八)--内存管理
目录 引入: 一、C中的内存布局 1.内存区域 2.示例变量存储位置说明 二、C语言中动态内存管理 三、C内存管理方式 1.new/delete操作内置类型 2.new和delete操作自定义类型 四、operator new与operator delete函数(重要点进行讲解) …...

C# 企业微信机器人推送消息 windows服务应用程序的使用
C# 企业微信机器人推送消息 先添加一个机器人! 然后查看机器人就可以得到一个 webhook 特别特别要注意:一定要保护好机器人的webhook地址,避免泄漏! 然后开始写代码 ,只需要httpPost 调用一下这个地址就可以发送消息了。 首先我…...

社区交流系统设计与实现
社区交流系统设计与实现 1. 系统概述 社区交流系统是一个基于PHP和SQL的Web应用程序,旨在为用户提供一个互动交流的平台。该系统允许用户注册、发布帖子、回复帖子、查看其他用户的帖子和回复,以及管理个人资料,提高用户之间的互动和信息共享…...

【模型学习之路】手写+分析bert
手写分析bert 目录 前言 架构 embeddings Bertmodel 预训练任务 MLM NSP Bert 后话 netron可视化 code2flow可视化 fine tuning 前言 Attention is all you need! 读本文前,建议至少看懂【模型学习之路】手写分析Transformer-CSDN博客。 毕竟Bert是tr…...
Redis学习文档(常见面试题)
目录 Redis回收使用的是什么算法? Redis如何做大量数据插入? 为什么要做Redis分区? 你知道有哪些Redis分区实现方案? Redis分区有什么缺点? Redis持久化数据和缓存怎么做扩容? 分布式Redis是前期做还…...
【C++刷题】力扣-#594-最长和谐子序列
题目描述 和谐数组是指一个数组里元素的最大值和最小值之间的差别 正好是 1 。 给你一个整数数组 nums ,请你在所有可能的子序列中找到最长的和谐子序列的长度。 数组的 子序列是一个由数组派生出来的序列,它可以通过删除一些元素或不删除元素、且不改变…...

MoveIt 控制自己的真实机械臂【2】——编写 action server 端代码
完成了 MoveIt 这边 action client 的基本配置,MoveIt 理论上可以将规划好的 trajectory 以 action 的形式发布出来了,浅浅尝试一下,在 terminal 中运行 roslaunch xmate7_moveit_config_new demo.launch 报错提示他在等待 xmate_arm_control…...
C#制作学生管理系统
定义学生类 定义一个简单的类来表示学生,包括学号、姓名、性别、年龄、电话、地址。再给其添加一个方法利于后续添加方法查看学生信息。 //定义学生类 public class student {public int ID { get; set; }//开放读写权限public string Name { get; set; }public i…...

python Pandas合并(单元格、sheet、excel )
安装 Pandas 和 openpyxl 首先,确保已经安装了 Pandas 和 openpyxl。可以通过 pip 安装: pip install pandas openpyxl 创建 DataFrame import pandas as pd # 创建 DataFrame df1 pd.DataFrame({ 姓名: [张三, 李四, 王五], 年龄: [25, 30, 35]…...

OJ在线编程常见输入输出练习【JavaScript】
(注:本文是对【JavaScript Node 】 ACM模式,常见输入输出练习相关内容的介绍!!!) 牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ 一、ACM模式下的编辑页面 二、ACM模式下&a…...
新能源汽车空调系统:绿色出行的舒适保障
在新能源汽车迅速发展的今天,空调系统作为提升驾乘舒适度的重要组成部分,发挥着不可或缺的作用。新能源汽车空调系统主要由压缩机、冷凝器、节流装置和蒸发器四大件组成,它们协同工作,为车内提供适宜的温度和湿度环境。 一、压缩…...

Date工具类详细汇总-Date日期相关方法
# 1024程序员节 | 征文 # 目录 简介 Date工具类单元测试 Date工具类 简介 本文章是个人总结实际工作中常用到的Date工具类,主要包含Java-jdk8以下版本的Date相关使用方法,可以方便的在工作中灵活的应用,在个人工作期间频繁使用这些时间的格…...

TMUX1308PWR规格书 数据手册 具有注入电流控制功能的 5V 双向 8:1单通道和 4:1 双通道多路复用器芯片
TMUX1308 和 TMUX1309 为通用互补金属氧化物半导体 (CMOS) 多路复用器 (MUX)。TMUX1308 是 8:1单通道(单端)多路复用器,而 TMUX1309 是 4:1 双通道(差分)多路复用器。这些器件可在源极 (Sx) 和漏极 (Dx) 引脚上支持从 …...

证件照怎么换底色?简单又快速!不看后悔
一、引言 证件照在我们的生活中有着广泛的应用,无论是求职、考试还是办理各种证件,都需要用到不同底色的证件照。传统的换底色方法往往比较复杂,需要一定的专业技能和软件操作经验。但是现在,有了更简单快捷的方法,让你…...
Rust 基础语法与常用特性
Rust 跨界:全面掌握跨平台应用开发 第一章:快速上手 Rust 1.2 基础语法与常用特性 1.2.1 数据类型与控制流 数据类型 Rust 提供了丰富的内置数据类型,主要分为标量类型和复合类型。 标量类型 标量类型表示单一的值,Rust 中…...

一、开发环境的搭建
环境搭建步骤: 下载软件安装软件运行软件 其他: Visual studio 安装包文件:https://www.alipan.com/s/nd5RgzD4e3b 下载软件 在浏览器中搜索Visual studio,选择如图的选项 点击该区域,进入该页面,【或…...

Docker:存储原理
Docker:存储原理 镜像联合文件系统overlay镜像存储结构容器存储结构 存储卷绑定挂载存储卷结构 镜像 联合文件系统 联合文件系统Union File System是一种分层,轻量且高效的文件系统。其将整个文件系统分为多个层,层与层之间进行覆盖&#x…...

ts:数组的常用方法(push、pop、shift、unshift、splice、slice)
前端css中filter的使用 一、主要内容说明二、例子(一)、push方法(尾添加)1.源码1 (push方法)2.源码1运行效果 (二)、pop方法(尾删除)1.源码2(pop方…...
物联网网关确保设备安全
物联网(IoT)网关在确保设备安全方面扮演着至关重要的角色。 作为连接物联网设备和云端或企业系统的中介,物联网网关可以实施多种安全措施来保护设备和数据。 是物联网网关确保设备安全的关键方法: 1. 设备认证和授权 认证&…...

Vue学习笔记(五)
Class绑定 数据绑定的一个常见需求场景式操纵元素的CSS class列表,因为class是attribute,我们可以和其他attribute一样使用v-bind将它们和动态的字符串绑定。但是,在处理比较复杂的绑定时,通过拼接生成字符串是麻烦且易出错的。因此…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

Qt的学习(一)
1.什么是Qt Qt特指用来进行桌面应用开发(电脑上写的程序)涉及到的一套技术Qt无法开发网页前端,也不能开发移动应用。 客户端开发的重要任务:编写和用户交互的界面。一般来说和用户交互的界面,有两种典型风格&…...

Java数组Arrays操作全攻略
Arrays类的概述 Java中的Arrays类位于java.util包中,提供了一系列静态方法用于操作数组(如排序、搜索、填充、比较等)。这些方法适用于基本类型数组和对象数组。 常用成员方法及代码示例 排序(sort) 对数组进行升序…...

Python环境安装与虚拟环境配置详解
本文档旨在为Python开发者提供一站式的环境安装与虚拟环境配置指南,适用于Windows、macOS和Linux系统。无论你是初学者还是有经验的开发者,都能在此找到适合自己的环境搭建方法和常见问题的解决方案。 快速开始 一分钟快速安装与虚拟环境配置 # macOS/…...

EasyRTC音视频实时通话功能在WebRTC与智能硬件整合中的应用与优势
一、WebRTC与智能硬件整合趋势 随着物联网和实时通信需求的爆发式增长,WebRTC作为开源实时通信技术,为浏览器与移动应用提供免插件的音视频通信能力,在智能硬件领域的融合应用已成必然趋势。智能硬件不再局限于单一功能,对实时…...

职坐标物联网全栈开发全流程解析
物联网全栈开发涵盖从物理设备到上层应用的完整技术链路,其核心流程可归纳为四大模块:感知层数据采集、网络层协议交互、平台层资源管理及应用层功能实现。每个模块的技术选型与实现方式直接影响系统性能与扩展性,例如传感器选型需平衡精度与…...

简单聊下阿里云DNS劫持事件
阿里云域名被DNS劫持事件 事件总结 根据ICANN规则,域名注册商(Verisign)认定aliyuncs.com域名下的部分网站被用于非法活动(如传播恶意软件);顶级域名DNS服务器将aliyuncs.com域名的DNS记录统一解析到shado…...