20240414-C++-Concepts
C++ Concepts概念(Concepts)是C++20中引入的一项特性,它们是对模板参数的约束,用于指定模板参数必须满足的接口(例如,一组必需的函数、类型、操作符等)和语义要求。概念旨在提高模板编程的表达力和安全性,通过更清晰的语义来改善编译器错误信息,并促使编写更干净、更易于理解的代码。 在C++20之前,模板编程通常是通过特化和重载来实现各种约束的,这往往会产生冗长的错误信息,让人难以理解实际的问题所在。概念允许你以更声明式的方式指定约束,使得模板的意图更明确,能够在编译时提早发现错误,同时生成更有用的错误信息。 以下是一些使用概念的优势: 提升代码清晰度: 概念使得模板的要求变得明确,可以直接在函数模板的声明中看到对类型参数的要求。 改进错误信息: 当传递给模板的类型不符合概念要求时,编译器可以提供更加直接的错误信息,这有助于快速定位问题。 简化模板定义: 概念能够替代复杂的SFINAE(Substitution Failure Is Not An Error)表达式,简化模板的定义。 提供更好的工具支持: 由于概念的语义更加明确,IDE和其他代码分析工具能够提供更...
20240627-WebServer-0
在设计一个WebServer时,选择线程池还是协程取决于你的具体需求、预期的并发量、以及你对编程模型的偏好。下面我将从几个方面分析线程池和协程的优缺点,以帮助你做出决策。 线程池优点: 成熟稳定:线程池是多线程编程中常用的技术,已经非常成熟和稳定。 易于理解:线程的概念在操作系统层面有明确的定义,对于大多数开发者来说,线程池模型更容易理解和实现。 兼容性好:几乎所有的操作系统和编程语言都支持线程,因此线程池的兼容性非常好。 缺点: 资源消耗:每个线程都需要一定的内存和上下文切换开销,当并发量很大时,线程池可能会消耗大量系统资源。 编程复杂性:多线程编程需要处理同步和竞态条件,这可能会增加编程的复杂性。 协程优点: 资源高效:协程是一种轻量级的用户态线程,切换开销远小于系统线程,因此在相同的资源下可以支持更高的并发量。 编程简单:协程通常是非抢占式的,开发者可以控制协程的切换时机,这使得并发编程更加简单,减少了锁和同步的需求。 适合IO密集型任务:协程特别适合IO密集型的应用,如Web服务器,因为它们可以在等待IO时让出控制权,从而提高并发处理能力。 缺点: 生态和兼...
LeetCode-189.轮转数组
189.轮转数组题目描述给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 示例 1: 123456输入: nums = [1,2,3,4,5,6,7], k = 3输出: [5,6,7,1,2,3,4]解释:向右轮转 1 步: [7,1,2,3,4,5,6]向右轮转 2 步: [6,7,1,2,3,4,5]向右轮转 3 步: [5,6,7,1,2,3,4] 示例 2: 12345输入:nums = [-1,-100,3,99], k = 2输出:[3,99,-1,-100]解释: 向右轮转 1 步: [99,-1,-100,3]向右轮转 2 步: [3,99,-1,-100] 提示: 1 <= nums.length <= 105 -231 <= nums[i] <= 231 - 1 0 <= k <= 105 进阶: 尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。 你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗? 解题方法一因为是轮转,所以很明显只需要考虑0...
LeetCode-80.删除有序数组中的重复项II
80.删除有序数组中的重复项II题目描述给你一个有序数组 nums ,请你** 原地** 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。 说明: 为什么返回数值是整数,但输出的答案是数组呢? 请注意,输入数组是以**「引用」**方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 你可以想象内部操作如下: 12345678// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝int len = removeDuplicates(nums);// 在函数里修改输入数组对于调用者是可见的。// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。for (int i = 0; i < len; i++) { print(nums[i]);} 示例 1: 123输入:nums = [1,1,1,2,2,3]输出:5, nums = [1,1,2,2,3]解释:函数应返回新长度 l...
20240409-Rust-03-数据类型
数据类型 Rust 的每个值都有确切的数据类型(data type),该类型告诉 Rust 数据是被指定成哪类数据,从而让 Rust 知道如何使用该数据。在本节中,我们将介绍两种数据类型:标量类型和复合类型。 请记住 Rust 是一种静态类型(statically typed)的语言,这意味着它必须在编译期知道所有变量的类型。 当类型可能是多种情况或编译器无法推导和确定时,必须加上一个类型标注: 1let guess: u32 = "42".parse().expect("Not a number!"); 标量类型 标量(scalar)类型表示单个值。Rust 有 4 个基本的标量类型:整型、浮点型、布尔型和字符。你可能从其他语言了解过这些类型。下面我们深入了解它们在 Rust 中的用法。 整数类型 整数(integer)是没有小数部分的数字。我们在第 2 章使用过一个整数类型(整型),即 u32 类型。此类型声明表明它关联的值应该是占用 32 位空间的无符号整型(有符号整型以 i 开始,i 是英文单词 integer 的首字母,与之...
20240410-Rust-00-前言
你说得对,但是Rust 是由 Mozilla 自主研发的一款全新零开销抽象编程语言。语言采用一种被称作「RAII」 的资源管理机制,在这里,退出作用域的对象将触发「drop」方法,进而被销毀。你将扮演一位名为「Rustacean」的神秘角色,在编码过程中邂逅形状各异、形式独特的生命周期们,和它们一起击败编译错误,找回失去的内存安全——同时,逐步发掘「servo」的真相。
20240410-Rust-04-语句与表达式与函数
语句与表达式与函数函数main函数是程序入口,fn是用来声明新函数的关键字。 Rust代码中的函数和变量名都使用下划线命名法(snake case,直译为蛇形命名法)规范风格。此命名法中,所有字母都是小写并使用下划线分隔单词。 与C/C++不同的是,Rust 不关心函数定义于何处,只要定义了就行。 形参必须标注类型。 在函数签名中,必须声明每个参数的类型。这是一个 Rust 设计中经过慎重考虑的决定:要求在函数定义中提供类型标注,意味着编译器几乎从不需要你在代码的其他地方注明类型来指出你的意图。 示例: 1234567fn main() { print_labeled_measurement(5, 'h');}fn print_labeled_measurement(value: i32, unit_label: char) { println!("The measurement is: {}{}", value, unit_label);...
20240410-Rust-05-控制流
控制流 根据条件是否为真来决定是否执行某些代码,或根据条件是否为真来重复运行一段代码,是大部分编程语言的基本组成部分。Rust 代码中最常见的用来控制执行流的结构是 if 表达式和循环。 if 表达式每个分支的代码块都必须以{}包裹,哪怕只有一行或一条表达式。 条件(谓词)表达式不必(不是不可以)使用()包裹。 条件(谓词)表达式必须是布尔值,Rust不会进行非布尔到布尔的自动类型转换。 在 let 语句中使用 if因为 if 是一个表达式,我们可以在 let 语句的右侧使用它来将结果赋值给一个变量,例如在示例 3-2 中: 文件名: src/main.rs 123456fn main() { let condition = true; let number = if condition { 5 } else { 6 }; println!("The value of number is: {}", number);} 示例 3-2:将 if 表达式...
20240411-Rust-06-所有权
所有权 所有权(系统)是 Rust 最为与众不同的特性,它让 Rust 无需垃圾回收器(garbage collector)即可保证内存安全。因此,理解 Rust 中所有权的运作方式非常重要。在本章中,我们将讨论所有权以及相关功能:借用、slice 以及 Rust 如何在内存中存放数据。 什么是所有权?Rust 的核心功能(之一)是 所有权(ownership)。虽然该功能很容易解释,但它对语言的其他部分有着深刻的影响。 所有运行的程序都必须管理其使用计算机内存的方式。一些语言中具有垃圾回收机制,在程序运行时不断地寻找不再使用的内存;在另一些语言中,开发者必须亲自分配和释放内存。Rust 则选择了第三种方式:通过所有权系统管理内存,编译器在编译时会根据一系列的规则进行检查。在运行时,所有权系统的任何功能都不会减慢程序。 因为所有权对很多开发者来说都是一个新概念,需要一些时间来适应。好消息是随着你对 Rust 和所有权系统的规则越来越有经验,你就越能自然地编写出安全和高效的代码。持之以恒! 当你理解了所有权,你将有一个坚实的基础来理解那些使 Rust 独特的功能。在本章中,你将通...
20240320-配置GitHub-SSH默认使用443端口
配置GitHub SSH默认使用443端口1.测试443端口是否可用首先测试一下使用443端口进行GitHub SSH连接: 1ssh -T -p 443 git@ssh.github.com 如果一切正常,那么你应该得到如下输出: Hi UserName! You’ve successfully authenticated, but GitHub does not provide shell access. 2.配置SSH使用443端口SSH客户端配置文件 12# 全局配置文件:/etc/ssh/ssh_config# 用户配置文件:~/.ssh/config # 如果不存在则创建 在你的SSH客户端配置文件中增加以下内容: 1234Host github.com Hostname ssh.github.com Port 443 User git 再次测试是否有效: 1ssh -T git@github.com 或拉取仓库: 1git clone git@github.com:UserName/RepoName.git
20240327-LeetCode-15.三数之和
15.三数之和题目描述给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请 你返回所有和为 0 且不重复的三元组。 **注意:**答案中不可以包含重复的三元组。 示例 1: 12345678输入:nums = [-1,0,1,2,-1,-4]输出:[[-1,-1,2],[-1,0,1]]解释:nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。注意,输出的顺序和三元组的顺序并不重要。 示例 2: 123输入:nums = [0,1,1]输出:[]解释:唯一可能的三元组和不为 0 。 示例 3:...
20240408-Rust-01-猜数字游戏
猜数字游戏123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960use rand::Rng;use std::cmp::Ordering;use std::io;/** * The main function of the program. * It starts the game by printing a welcome message, generating a secret number, and then entering a loop where it prompts the user to guess the number. * It continues to loop until the user guesses the correct number. */fn main() { println!("Guess the number!"); /** ...
20240409-Rust-02-变量与可变性
变量与可变性1234567891011121314151617181920212223242526272829#![allow(unused)]fn main() { // 变量默认是不可变的,如要声明可变变量,应使用mut关键字 // let x = 5; let mut x = 5; println!("The value of x is {}", x); // 5 x = 6; println!("The value of x is {}", x); // 6 // 常量,命名约定是全部字母大写,并以下划线分隔单词 // 在声明的作用域内,常量在程序运行的整个过程中都有效 const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3; // 遮蔽(shadow),可以通过使用相同的变量名并重复使用 let 关键字来遮蔽之前的变量 let x = 5; let x = x + 1; ...
Linux内核态赋予进程root权限
一、Linux中进程的用户管理在Linux中,每个进程都拥有真实用户ID (==uid==)和真实组ID (==gid==),有效用户ID (==euid==)和有效组ID (==egid==),保存的设置用户ID (==suid==)和保存的设置组ID (==sgid==),另外地,还有文件系统用户ID (==fsuid==)和文件系统组ID (==fsgid==)。 (1) 真实用户、组 (uid/gid):指的是进程的实际所有者和所属组,一般就是执行此进程的用户。 (2) 有效用户、组 (euid/egid):用来判断进程执行各种操作的权限。 (3) 保存的设置用户、组 (suid/sgid):是有效用户、组的副本,主要用来还原...
20240326-Typora激活教程
::: tip 声明本博客仅以学习为目的进行记录,请支持正版,并将本博客提及相关文件于24h内删除。::: 1.安装原版Typora安装过程略过 2.克隆相关仓库方式一直接克隆Yporaject (此项目对原两个项目进行了合并),好处是一键编译即可,坏处是此项目并未和原项目代码同步。 12# 可以直接克隆本项目的仓库, depth=1 表示仅克隆最新版本,以减少等待时间git clone https://github.com/hazukieq/Yporaject.git --depth=1 方式二克隆原项目仓库,好处是保持最新版,坏处是稍微麻烦一点。 1234567891011121314151617# 原项目仓库, depth=1 表示仅克隆最新版本,以减少等待时间git clone https://github.com/DiamondHunters/NodeInject --depth=1 git clone https://github.com/DiamondHunters/NodeInject_Hook_example --depth=1# 建立 Yproraject ...
20240328-Debian12根分区扩容记录
[!WARNING] 以下操作可能会导致包括但不仅限于数据丢失、无法启动等问题,严重时您可能需要重装系统,如要继续,请确保已做好数据备份等准备工作。 Debian12根分区扩容记录前言情况是这样的,有一台Debian12的机器,磁盘分区信息如下: 12345678root@xxx:~# df -ThFilesystem Type Size Used Avail Use% Mounted onudev devtmpfs 3.8G 0 3.8G 0% /devtmpfs tmpfs 775M 488K 775M 1% /run/dev/vda1 ext4 19G 1.1G 17G 7% /tmpfs tmpfs 3.8G 0 3.8G 0% /dev/shmtmpfs tmpfs 5.0M 0 5.0M 0% /run/locktmpfs tmpfs 77...
Linux内存分页及虚拟地址到物理地址的计算
前言 MMU(内存管理单元): MMU的主要作用是地址的转换,将虚拟地址转换为物理地址。不连续的物理地址也可以映射为连续的虚拟地址。 待续。。。

