栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Missing Semester 与 现代 C++ 笔记

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Missing Semester 与 现代 C++ 笔记

文章目录
  • Missing Semester 与 现代 C++ 笔记
    • 基础知识
    • shell 语言
      • 快速上手shell
    • ViM 编辑器
      • code vim
    • Pipe 用例 / 数据处理
    • 承上启下

Missing Semester 与 现代 C++ 笔记 基础知识
  • 需要对 C 语言和面向对象有基本的了解
  • 需要对 Linux Shell 有基本的了解
  • 自测: 请回答以下几组问题并阅读以下几组代码

int 和 float 的计算机实现是什么?

float Q_rsqrt( float x ) {
  union { float f; uint32_t i; } y;
  float x2 = x * 0.5F;
  y.f = x;
  y.i = 0x5f3759df - ( y.i >> 1 );
  y.f = y.f * ( 1.5F - ( x2 * y.f * y.f ) );
  // y.f = y.f * ( 1.5F - ( x2 * y.f * y.f ) );
  return y.f;
}

类型转换

int i = 1;
char* pc = (char*)(&i);
if(pc[0] == 'x1') {
    puts("This system is little-endian");
} else {
    puts("This system is big-endian");
}

大括号与作用域

int main() {
   int i = 0;
   for ( ; i < ({
	   int r = rand();
	   printf("r == %dn", r);
	   (r + i)%10;
   }) ; i++ ); // gcc
   printf("i == %dn", i);
   
   return 0;
}

指针与地址 (现代 C++ 中, 应该使用 using)

T *p; p = &o; p = (T *) malloc(size);
T0 *p(T1, T2); p = ( T0 (*)(T1, T2) ) pf;

const T *p; T * const p;
int n; int * const np = &n; int *const *npp = &np;
// 指向指向 非const 的 int 的 const 指针的 非 const 指针

int (*(*foo)(double))[3] = NULL;
assert(foo == NULL);
foo = ( int (*(*)(double))[3] ) fp;
int bar = (*(*foo)(1.2))[1];

void (*signal(int sig, void (*func)(int)))(int);
// a better way
typedef void (*sighandler_t)(int);
sighandler_t signal(int, sighandler_t);
#include 

int main()
{
   int (*fp)(void) = &main;
   // int (*fp)(void) = main;
   // int (*fp)(void) = *main;
   int (**fpp)(void) = &fp;
   printf("fp == %pn", fp);
   printf("&fp == %pn", &fp);
   printf("&fpp == %pn", &fpp);
   
   return 0;
}

// fp == 0x401122 // main .text
// &fp == 0x7ffddaf5d8b8 // fp stack
// &fpp == 0x7ffddaf5d8b0 // fpp stack
// 函数调用也是运算符, 联系到函数调用的汇编实现, 一切就说的通了
// 在编译器眼中, &func == func
// file1.c
char s[64] = "Hello World!n";

// file2.c
extern char *s;
int main() {
  printf("%pn", s); // 防止 s 被优化掉
  // printf("%cn", s[0]; // Segmentation fault
  return 0;
}

// extern 既非强符号,也非弱符号。
// 无法匹配相同类型强符号之后就归入.bss节。
// gcc file1.c file2.c
// xxd a.out 会发现 "Hello World!n" 位于 .rodata 节

动态分配内存

volatile 变量是什么意思? 原子变量是什么意思?

echo hello world 的执行过程?

  • 文件系统如何通过 inode 管理? 目录项 (路径) 和 inode 的关系?
    • shell 的文件操作
      • pwd, cd (本质上是 shell 的函数, 而不是一个可执行的二进制文件, 至少在 Linux 上如此)
      • ls
      • cp, mv, rm, ln, ln -s
      • mkdir, rmdir (empty only)
      • touch
      • find -type(d,f) -name -mtime -size -4k -size +4G -exec rm {} ;
      • chmod, chown, ls -l
      • 其他磁盘驱动有关的命令 df 与 du (estimate) 的区别?
    • cat (head, tail, tee) 与 dd (DataDef) 的区别? (dd 可以调用 seek)
    • 重定向 >, < (>>, 1>, 2>, &>)
      • << 指定长文档的结束符
      • <<< 指定长字符串
      • 以上两种用法等同于stdin重定向为输入的长文档/长字符串
  • nc (NetCat) 与 curl (pup jq) 的区别? (curl 面向 HTTP)
  • echo 与 printf 的区别?
  • echo str, echo "str", echo 'str'
  • 桌面环境 (KDE plasma) 中程序的运行实际上也是 一个特殊的 shell 的子进程, 利用 pstree 命令可以观察到 plasmashell 的子进程有 code, netease, chrome.
  • 解释器提取 3 个 token, 依次是 echo, hello, world.
  • (不是布尔表达式; 没有管道;) 第一个 token, 也仅有这个 token, 指示一个可执行的二进制文件. 通过查找环境变量 (echo $PATH) 获得这个可执行目标文件的绝对路径 (实际上是 which echo 之一).
  • 之后的 2 个 token 是参数列表.
  • 执行 exec 库函数, 传入绝对路径和参数列表.
  • fork Shell 进程, 替换镜像, 高地址压入环境变量, 低地址 mmap 指令序列和数据 (.bss 初始化为 0). (实际上用户的虚拟地址有随机偏移.)
  • 从 _start 执行 echo, 通过系统调用, 把参数列表写到 stdout 上. _exit(status) 函数通过系统调用请求杀死进程, 给父进程发送信号 SIGCHLD, 父进程调用 wait 获得 status 作为返回值. (status 的语义是子进程的状态. 即, echo $? 结果是 0.)
# include 

__attribute__((constructor)) void hello() {
    printf("hellon");
}

// See also: atexit(3)
__attribute__((destructor)) void goodbye() {
    printf("goodbyen");
}

int main() {
    return 0;
}

环境变量

  • 函数 (或者仅仅是一条命令) 会在当前的 shell 环境中执行, 函数可以对环境变量进行更改.
  • 脚本会在单独的进程中执行 (脚本作为参数传给 SheBang 指定的解释器程序), 脚本需要使用 export 将环境变量导出, 并将值传递给环境变量.
# leaf @ DAVE in ~/Roland/book/Cpp_Missing [16:14:15]
$ sudo find -L /sys/class/backlight -maxdepth 2 -name 'brightness' 
/sys/class/backlight/intel_backlight/brightness
find: File system loop detected; ‘/sys/class/backlight/intel_backlight/subsystem’ is part of the same file system loop as ‘/sys/class/backlight’.

# leaf @ DAVE in ~/Roland/book/Cpp_Missing [16:14:27] C:1
$ sudo echo 50000 > /sys/class/backlight/intel_backlight/brightness
zsh: permission denied: /sys/class/backlight/intel_backlight/brightness

# leaf @ DAVE in ~/Roland/book/Cpp_Missing [16:14:35] C:1
$ echo 50000 | sudo tee /sys/class/backlight/intel_backlight/brightness
50000
  • /sys/
  • File system loop 与 ln? (ls -i)
  • sudo 的位置, 时机?

grep (GlobalREgexPrint) 与 awk (family names of its authors) 的区别?

  • grep 查找正则 pattern
    • grep -C Context
    • grep -v Invert
  • awk 是一个语言, Linux 上运行的是其实现 gawk.
@include "filename"
@load "filename"
@namespace "name"
pattern { action statements }
function name(parameter list) { statements }

管道 | 与重定向的区别?

  • 管道将前者的 stdout 作为后者的 stdin
  • 重定向将程序的 stdout (和 stderr) 替换为其他文件

echo cat xargs 的区别?

find . -type f | xargs -d "n" ls -lt | head
# 不含目录项(文件夹) 按时间列出 仅列出前几项
  • echo ... … -> stdout
  • cat filepath filepath 的内容 -> stdout
  • xargs command ... 执行 command stdin …

su, sudo, useradd, usrdel

jobs 与 ps 的区别?

man

public (protected) private

this 指针, T & 成员函数返回 (*this)

  • istream &read(instream &is, T &obj);
  • ostream &read(onstream &os, T &obj);

构造函数, 析构函数, 拷贝与赋值

友元

shell 语言
foo=bar     # foo <- 'bar'
foo = bar   # 向 foo 传入 ['=', 'bar']
echo "$foo" # 特殊符号, 字段的替换
# "$Foo" 为空串
echo '$foo' # 字符串
#!/bin/bash
# 通过 source 加载函数以及环境变量
savepwd(){
    echo "$(pwd)" > $HOME/savepwd.cache
    echo "save pwd $(pwd)"
}
cdoldpwd(){
    # 注意小括号和引号的关系
    cd "$(cat "$HOME/savepwd.cache")"
}
mcd () {
    mkdir -p "$1"
    cd "$1"
}
  • $0 - 脚本名
  • $1 到 $9 - 脚本的参数。 $1 是第一个参数,依此类推。
  • $@ - 所有参数
  • $# - 参数个数
  • $? - 前一个命令的返回值
  • $$ - 当前脚本的进程识别码
  • !! - 完整的上一条命令,包括参数。常见应用:当你因为权限不足执行命令失败时,可以使用 sudo !! 再尝试一次。
  • $_ - 上一条命令的最后一个参数。
echo "Starting program at $(date)"
# date会被替换成日期和时间

echo "Running $0 with $# arguments with pid $$"

for file in "$@"; do
    grep foobar "$file" > /dev/null 2> /dev/null
    # 我们将标准输出流和标准错误流丢弃
    # 如果模式没有找到, 则grep退出状态 != 0
    if [[ $? -ne 0 ]]; then
    # [ ] 是 test 的语法糖 (同义词)
    # [[ ]] 是 bash 的关键字
        echo "File $file does not have any foobar, adding one"
        echo "# foobar" >> "$file"
    fi
done
convert image.{png,jpg}
# convert image.png image.jpg

cp /path/{foo,bar,jia}.sh /newpath
# cp /path/foo.sh /path/bar.sh /path/jia.sh /newpath

rm foo?
rm foo*

# 也可以结合通配使用
mv *{.py,.sh} folder

mkdir foo bar
# 创建foo/a, foo/b, foo/c, bar/a, bar/b, bar/c
touch {foo,bar}/{a..c}
touch foo/x bar/y

diff <(ls foo) <(ls bar)
# 为什么不是 diff $(ls foo) $(ls bar)
false || echo "not short circuiting"
true && echo "not short circuiting"
echo "this will" ; echo "always run" ;
  • shellcheck
  • tldr (TooLongDon’tRead)
  • locate fd 作为 find 的替代品
  • rg ag ack 作为 grep 的替代品
  • fzf 改进 history
  • fasd, autojump 快速查找文件
    • broot nnn ranger 改进文件管理
#!/usr/bin/env bash

n=$(( RANDOM % 100 ))
# 双小括号是 let 语句的语法糖, 而且是 POSIX 标准.
# 意义是可以使用类似 C 的语法

if [[ n -eq 0 ]]; then
    echo "Finished!"
    >&2 echo "End with n==$n"
    exit 1
fi

# And 符号在右侧提示文件描述符 >&1 >&2
# 左侧的文件描述符直接书写 1> 2>
# And 符号在左侧是语法糖, &> 展开成 1> 2>

echo "Running."
count=0
while true
do
    ./random_try.sh &> /dev/null
    if [[ $? -ne 0 ]]; then
        echo "in total $count times"
        exit 0
    fi
    ((count++))
done

count=0
for ((count=1;;count++))
do
    ./random_try.sh &> /dev/null
    if [[ $? -ne 0 ]]; then
        echo "in total $count times"
        exit 0
    fi
done

count=0
until [[ "$?" -ne 0 ]];
do
    count=$((count+1))
    ./random_try.sh &> /dev/null
done
echo "in total $count times"

正则表达式

  • . 除换行符之外的"任意单个字符"
  • * 匹配前面字符零次或多次
  • + 匹配前面字符一次或多次
  • [abc] 匹配 a, b 和 c 中的任意一个
  • (RX1|RX2) 任何能够匹配RX1 或 RX2的结果
  • ^ 行首
  • $ 行尾

其他

  • ? 非贪婪 (本意是匹配恰好一个字符) sed 不支持 perl 支持
    perl -pe PATTERN
    
  • [^ ]+ 匹配任意非空且不包含空格的序列
快速上手shell

cd, ls, tree, find.

cd -
find . -name FileName

tldr

ctrl+left ctrl+right home end 快速编辑命令 跳转

### workspace
mkdir ~/mine/
mkdir ~/mine/scripts/
cd ~/mine/scripts/
vim filename.sh

### activate
chmod +x filename.sh
mkdir ~/bin/
ln -s $(readlink -f filename.sh) ~/bin/filename
updcmd=$(printf "nnexport PATH=$PATH:~/bin/n")
echo $updcmd >> ~/.bashrc
source ~/.bashrc

TODO tmux oh_my_zsh vim.netrw(:Rexplore)

ViM 编辑器

buffer

  • :q 退出(关闭窗口)
  • :w 保存(写)
  • :wq 保存然后退出
  • :e {文件名} 打开要编辑的文件
  • :ls 显示打开的缓存
  • :help {标题} 打开帮助文档

normal

  • 基本移动: hjkl (左, 下, 上, 右)
  • 词: w (下一个词), b (词初), e (词尾) +(下一行行首) -(上一行行首) ( ) (句子首位)
  • 行: 0 (行初), ^ (第一个非空格字符), $ (行尾)
  • 屏幕: H (屏幕首行), M (屏幕中间), L (屏幕底部)
  • 翻页: Ctrl-u (上翻), Ctrl-d (下翻)
  • 文件: gg (文件头), G (文件尾)
  • 行数: :{行数} 或者 {行数}G
  • 杂项: % (找到配对,比如括号或者 之类的注释对)
  • 查找: f{字符}, t{字符}, F{字符}, T{字符}
    • 查找/到 向前/向后 在本行的{字符}
    • , / ; 用于导航匹配
  • 搜索: /{正则表达式}, n / N 用于导航匹配
  • m 标记,' ` 跳转到标记

visual

  • 可视化:v
  • 可视化行: V
  • 可视化块:Ctrl+v

insert

  • i 进入插入模式
    • 但是对于操纵/编辑文本,不单想用退格键完成
  • O / o 在之上/之下插入行
  • d{移动命令} 删除 {移动命令}
    • 例如, dw 删除词, d$ 删除到行尾, d0 删除到行头。
  • c{移动命令} 改变 {移动命令}
    • 例如, cw 改变词
    • 比如 d{移动命令} 再 i
  • x 删除字符(等同于 dl)
  • s 替换字符(等同于 xi)
  • 可视化模式 + 操作
    • 选中文字, d 删除 或者 c 改变
  • u 撤销, 重做
  • y 复制 (其他一些命令比如 d 也会复制)
  • p 粘贴
  • ~ 改变字符的大小写

计数来结合“名词”和“动词”,这会执行指定操作若干次。

  • 3w 向前移动三个词
  • 5j 向下移动5行
  • 7dw 删除7个词

修饰语改变“名词”的意义。修饰语有 i,表示“内部”,和 a, 表示“周围”。

  • ci( 改变当前括号内的内容
  • ci[ 改变当前方括号内的内容
  • da’ 删除一个单引号字符串, 包括周围的单引号

. 重复上一个动作 q{字母} 录制 q 结束录制 @{字母} 重复 录制时可以递归调用该宏 q{字母}q 清除宏

/ ? 查找 n N 跳转到结果 * # 快速

:s 替换 例如 %s/[.*]((.*))/1/g 将有命名的 Markdown 链接替换成简单 URLs & 同 :s 重复上一个替换

:sp :vsp 分割 Ctrl+w 先导键

:r 读入

:e 新建 buffer
bn bp 切换 buffer

:tabnew 新建 tab
gt gT 切换 tab

Q 进入 Ex 模式

H M L 页面

J 合并行

code vim

跳转上一位置 alt+left alt+right / ctrl+i ctrl+o

跳转段落 / ctrl+u ctrl+d { }

括号跳转 ctrl+shift+pipe / percent

快速插入 ctrl+enter ctrl+shift+enter / o O

上下跳转 up down / gk gj

光标位置不变 页面上下移动 ctrl+up ctrl+down / ctrl+e ctrl+y

Pipe 用例 / 数据处理

字符串运算:

  • gerp
  • awk
  • sed (弱)
  • tr (替换)
  • diff (比较不同)
# 在远端首先过滤,再发送过滤好的流
ssh SEVER_NAME 'journalctl | grep sshd | grep "Disconnected from"' > ssh.log
less ssh.log

# 用 sed 处理构成的表格的流
cat ssh.log
 | grep sshd
 | grep "Disconnected from"
 | sed -E 's/.*Disconnected from (invalid |authenticating )?user (.*) [^ ]+ port [0-9]+( [preauth])?$/2/'
 | sort | unique -c # count
 | sort -nk1,1 # number, [1,1+1) 列
 | tail -n10
 | awk '{print $2}' | paste -sd, # 合并行, 并选择分隔符
# sort -r 或者 head 实现倒序
# uniq 只能过滤相邻的行, 所以必须先排序
# 正则表达式中 n awk 中 $n 的含义类似 shell
awk '$1 == 0 && $2 ~ /^[^ ]+$/ {print $0} | wc -l'

或者使用 << / <<< 向 awk 输入以下语句:

BEGIN { count = 1 }
$1 == 0 && $2 ~ /^[^ ]+$/ { count += 1 }
END { print count }

数学运算:

  • bc
  • R --slave -e python3 -c irb …

gnuplot 绘制图标

承上启下

missing semester 之后的内容包括

  • 元编程的思想
  • 日志, 调试与性能分析
    • 考虑增加 gdb 内容
  • (echo hello world 例子的深入) 命令行环境
  • git 的使用
  • docker, github, ssh

与开发密切相关. 我们暂且忽略, 首先补全 C++ 面向对象的基础知识.

  • c n a m e verb|c|name cname () 与 n a m e .h nameverb|.h| name.h 的区别: 是否位于 std 命名空间.
  • 机器无关类型: 引入了 std::string::size_type 类似 size_t .
  • 迭代器仅支持自增与自减, 形式上与指针相同. 为此, C++ 为 char a[] 引入了函数 begin end.
# include 

int main (int argc, char *argv[], char *envp[]) {
    for ( auto it = std::begin(argv[0]);
          it != std::end(argv[0]);
          it++ ) { }
}
  • auto, decltype()
  • const int *pci, int *const cpi, constexpr int *cpi
for (auto &c : str) { }
  • throw, try, catch
// 常见异常
# include 
# include 
# include 
# include 
  • 重载
  • 初始化
# include
using uint_list = std::vector;
int main() {
    // 构造函数传入参数
    uint_list x{4};   // [rand, rand, rand, rand]
                      // 与 allocator 有关
    uint_list y(4,0); // [0, 0, 0, 0]
    // 构造函数传入 initializer_list
    uint_list z{4,0}; // [4, 0]
    return 0;
}



// 常量初始化, 引用初始化

// 聚合初始化 (数组, POD)
T array[3] = {para0, para1}; 
T *parray[3] = {new T(para0), new T(para1) };

static T obj; T(); T obj{}; T obj = {}; // 零初始化
T obj; new T; new T(); // 默认初始化
T obj(); T obj{}; T(); T{}; new T{}; new T(); // 值初始化
T obj(paras, ...); // 直接初始化
 T obj{paras}; // 直接初始化
static_cast(another); // 直接初始化
// 闭包内通过捕获的参数初始化
// T::T : Tplus() { ... } T::T : Tplus{} { ... }

T{paras, ...}; T obj{paras, ...}; new T{paras, ...}; // 直接列表初始化
T obj = {paras, ...}; obj = {paras, ...}; // 复制列表初始化
f({paras, ...});  // 复制列表初始化
int x0; // 如果在栈上 warning: 'x' is used uninitialized [-Wuninitialized]
static int x_static; // 如果在 .bss 节(全局变量),被操作系统初始化为零。
int x1{}; // int 执行零初始化
int x2(); // 这是函数声明, 没有函数定义无法链接
int x3 = {}; // 这也是“零初始化”的语法
int *px0 = new int; // int 执行零初始化
int *px1 = new int(); // 这也是“零初始化”的语法
int *px2 = new int{}; // 这也是“零初始化”的语法

class cComplex {public: double re; double im; Complex()=default;};
struct sComplex {double re; double im;};

cComplex cc0(); sComplex sc0(); // warning: empty parentheses were disambiguated as a function declaration [-Wvexing-parse]
                                // g++ 认为是函数声明
sComplex sc1{}; // 执行零初始化
sComplex sc2 = {}; // 这也是“零初始化”的语法
cComplex *pcc0 = new cComplex(); // 执行默认构造函数,初始化为0
sComplex *psc0 = new sComplex(); // 执行零初始化
sComplex *psc1 = new sComplex{}; // 这也是“零初始化”的语法



struct A { int x; int y; int z; };
// A a{.y = 2, .x = 1}; // 错误:指派符的顺序不匹配声明顺序
A b{.x = 1, .z = 2}; // OK:b.y 被初始化为 0 Warning: missing initializer for member 'main()::A::y' [-Wmissing-field-initializers]

struct B {
  string x;
  unsigned int y = -1U;
  int z = -1;
};
B{.z=0}  // 以 {} 初始化 x,这样会调用默认构造函数
          // 然后以 = -1U 初始化 y
          // 然后以 = 0 初始化 z

struct S {
    int x;
    struct T {
        int i;
        int j;
        int k[3];
    } y;
};
// 等价
S s0 = { 1, { 2, 3, {4, 5, 6} } };
S s1 = {1,2,3,4,5,6};
S s2{ 1, { 2, 3, {4, 5, 6} } };
S s3{1,2,3,4,5,6};
 
// 类似指派符
enum Foo { A, B, C=10, D, E=1, F, G=F+C};
// A=0, B=1, C=10, D=11, E=1, F=2, G=12



// ===== C中合法,C++中不合法!=====

 数组
 error: ISO C++ does not allow C99 designated initializers [-Wpedantic]

int array0[5] = {[4]=5,[0]=1,2,3,4}; // 保有 1,2,3,4,5
int array1[MAX] = { // 开始初始化 a[0] = 1, a[1] = 3, ...
    1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0
};
// 对于 MAX=6 ,数组保有 1,8,6,4,2,0
// 对于 MAX=13 ,数组保有 1,3,5,7,9,0,0,0,8,6,4,2,0(“稀疏数组”)

 乱序
 warning: missing initializer for member 'main()::A::x' [-Wmissing-field-initializers]
 warning: missing initializer for member 'main()::A::y' [-Wmissing-field-initializers]
struct A { int x; int y; int z; };
A a0{.z = 3, .y = 2, .x = 1};

 混合
 error: either all initializer clauses should be designated or none of them should be
A a1{.x=1, 2, 3};

 嵌套
 error: expected primary-expression before '.' token
struct B {A a;}
B b0{.a.x=1};



// 调用 T::T()
T obj; new T; new T(); // 默认初始化
T obj(); T obj{}; T(); T{}; new T{}; new T(); // 值初始化

// 调用相应参数的 T::T(para0, ...)
T obj(para0, ...); new T(para0, ...);

// 调用 T::T(std::initializer_list)
T obj{item0, ...}; new T{item0, ...}; // 称作:直接列表初始化
T obj = {item0, ...}; // 称作:复制列表初始化
  • Allocator ⚠这是知乎上摘抄的一段代码,原链接找不到了.
// allocator

#include 

template  class MyAllocator{
public:
    //下面是类型别名,实现中的可选项
    using value_type = T;
    using pointer = T *;
    using const_pointer = const T *;

    using void_pointer = void *;
    using const_void_pointer = const void *;

    using size_type = size_t;
    using difference = std::ptrdiff_t;

    //重新绑定函数
    template 
    struct rebind{
        using other = MyAllocator;
    };

    MyAllocator() = default;
    ~MyAllocator() = default;

    //分配内存
    pointer allocate(size_type numObjects){
        allocCount += numObjects;
        std::cout << "MyAllocator::allocate 分配内存对象个数: " << numObjects << std::endl;
        return static_cast(operator new(sizeof(T) * numObjects));
    }

    //分配内存
    pointer allocate(size_type numObjects, const_void_pointer hint){

        return allocate(numObjects);
    }

    //释放内存
    void deallocate(pointer p, size_type numObjects){
        std::cout << "MyAllocator::deallocate 释放内存对象个数: " << numObjects << std::endl;
        allocCount = allocCount - numObjects;
        operator delete(p);
    }

    //分配器支持最大的内存数
    size_type max_size() const
    {
        return std::numeric_limits::max();
    }

    // //构造对象
    // template 
    // void construct(U *p, Args &&... args)
    // {

    //     new (p) U(std::forward(args)...);
    // }

    // //销毁对象
    // template 
    // void destroy(U *p)
    // {
    //     p->~U();
    // }

    //返回每次分配/删除的内存数
    size_type get_allocation_count() const {
        return allocCount;
    }

private:
    //统计当前内存的使用量
    size_type allocCount;
};

int main(){
    std::vector> v(0);
    for (size_t i = 0; i < 32; i++){
        v.push_back(i);
        std::cout << "[总计分配]" << v.get_allocator().get_allocation_count() << std::endl;
    }
    return 0;
}
MyAllocator::allocate 分配内存对象个数: 1
[总计分配]1
MyAllocator::allocate 分配内存对象个数: 2
MyAllocator::deallocate 释放内存对象个数: 1
[总计分配]2
MyAllocator::allocate 分配内存对象个数: 4
MyAllocator::deallocate 释放内存对象个数: 2
[总计分配]4
[总计分配]4
MyAllocator::allocate 分配内存对象个数: 8
MyAllocator::deallocate 释放内存对象个数: 4
[总计分配]8
[总计分配]8
[总计分配]8
[总计分配]8
MyAllocator::allocate 分配内存对象个数: 16
MyAllocator::deallocate 释放内存对象个数: 8
[总计分配]16
[总计分配]16
[总计分配]16
[总计分配]16
[总计分配]16
[总计分配]16
[总计分配]16
[总计分配]16
MyAllocator::allocate 分配内存对象个数: 32
MyAllocator::deallocate 释放内存对象个数: 16
[总计分配]32
[总计分配]32
[总计分配]32
[总计分配]32
[总计分配]32
[总计分配]32
[总计分配]32
[总计分配]32
[总计分配]32
[总计分配]32
[总计分配]32
[总计分配]32
[总计分配]32
[总计分配]32
[总计分配]32
[总计分配]32
MyAllocator::deallocate 释放内存对象个数: 32
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1029576.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号