Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
Go
Haskell
HLSL
Hook
Hylo
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Nim
Objective-C
Objective-C++
OCaml
OpenCL C
Pascal
Pony
Python
Racket
Ruby
Rust
Snowball
Scala
Solidity
Spice
Swift
LLVM TableGen
Toit
TypeScript Native
V
Vala
Visual Basic
Zig
Javascript
GIMPLE
c++ source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
6502-c++ 11.1.0
ARM GCC 10.2.0
ARM GCC 10.3.0
ARM GCC 10.4.0
ARM GCC 10.5.0
ARM GCC 11.1.0
ARM GCC 11.2.0
ARM GCC 11.3.0
ARM GCC 11.4.0
ARM GCC 12.1.0
ARM GCC 12.2.0
ARM GCC 12.3.0
ARM GCC 13.1.0
ARM GCC 13.2.0
ARM GCC 13.2.0 (unknown-eabi)
ARM GCC 4.5.4
ARM GCC 4.6.4
ARM GCC 5.4
ARM GCC 6.3.0
ARM GCC 6.4.0
ARM GCC 7.3.0
ARM GCC 7.5.0
ARM GCC 8.2.0
ARM GCC 8.5.0
ARM GCC 9.3.0
ARM GCC 9.4.0
ARM GCC 9.5.0
ARM GCC trunk
ARM gcc 10.2.1 (none)
ARM gcc 10.3.1 (2021.07 none)
ARM gcc 10.3.1 (2021.10 none)
ARM gcc 11.2.1 (none)
ARM gcc 5.4.1 (none)
ARM gcc 7.2.1 (none)
ARM gcc 8.2 (WinCE)
ARM gcc 8.3.1 (none)
ARM gcc 9.2.1 (none)
ARM msvc v19.0 (WINE)
ARM msvc v19.10 (WINE)
ARM msvc v19.14 (WINE)
ARM64 Morello gcc 10.1 Alpha 2
ARM64 gcc 10.2
ARM64 gcc 10.3
ARM64 gcc 10.4
ARM64 gcc 10.5.0
ARM64 gcc 11.1
ARM64 gcc 11.2
ARM64 gcc 11.3
ARM64 gcc 11.4.0
ARM64 gcc 12.1
ARM64 gcc 12.2.0
ARM64 gcc 12.3.0
ARM64 gcc 13.1.0
ARM64 gcc 13.2.0
ARM64 gcc 5.4
ARM64 gcc 6.3
ARM64 gcc 6.4
ARM64 gcc 7.3
ARM64 gcc 7.5
ARM64 gcc 8.2
ARM64 gcc 8.5
ARM64 gcc 9.3
ARM64 gcc 9.4
ARM64 gcc 9.5
ARM64 gcc trunk
ARM64 msvc v19.14 (WINE)
AVR gcc 10.3.0
AVR gcc 11.1.0
AVR gcc 12.1.0
AVR gcc 12.2.0
AVR gcc 12.3.0
AVR gcc 13.1.0
AVR gcc 13.2.0
AVR gcc 4.5.4
AVR gcc 4.6.4
AVR gcc 5.4.0
AVR gcc 9.2.0
AVR gcc 9.3.0
Arduino Mega (1.8.9)
Arduino Uno (1.8.9)
BPF clang (trunk)
BPF clang 13.0.0
BPF clang 14.0.0
BPF clang 15.0.0
BPF clang 16.0.0
BPF clang 17.0.1
BPF clang 18.1.0
BPF gcc 13.1.0
BPF gcc 13.2.0
BPF gcc trunk
EDG (experimental reflection)
EDG 6.5
EDG 6.5 (GNU mode gcc 13)
EDG 6.6
EDG 6.6 (GNU mode gcc 13)
FRC 2019
FRC 2020
FRC 2023
KVX ACB 4.1.0 (GCC 7.5.0)
KVX ACB 4.1.0-cd1 (GCC 7.5.0)
KVX ACB 4.10.0 (GCC 10.3.1)
KVX ACB 4.11.1 (GCC 10.3.1)
KVX ACB 4.12.0 (GCC 11.3.0)
KVX ACB 4.2.0 (GCC 7.5.0)
KVX ACB 4.3.0 (GCC 7.5.0)
KVX ACB 4.4.0 (GCC 7.5.0)
KVX ACB 4.6.0 (GCC 9.4.1)
KVX ACB 4.8.0 (GCC 9.4.1)
KVX ACB 4.9.0 (GCC 9.4.1)
M68K gcc 13.1.0
M68K gcc 13.2.0
M68k clang (trunk)
MRISC32 gcc (trunk)
MSP430 gcc 4.5.3
MSP430 gcc 5.3.0
MSP430 gcc 6.2.1
MinGW clang 14.0.3
MinGW clang 14.0.6
MinGW clang 15.0.7
MinGW clang 16.0.0
MinGW clang 16.0.2
MinGW gcc 11.3.0
MinGW gcc 12.1.0
MinGW gcc 12.2.0
MinGW gcc 13.1.0
RISC-V (32-bits) gcc (trunk)
RISC-V (32-bits) gcc 10.2.0
RISC-V (32-bits) gcc 10.3.0
RISC-V (32-bits) gcc 11.2.0
RISC-V (32-bits) gcc 11.3.0
RISC-V (32-bits) gcc 11.4.0
RISC-V (32-bits) gcc 12.1.0
RISC-V (32-bits) gcc 12.2.0
RISC-V (32-bits) gcc 12.3.0
RISC-V (32-bits) gcc 13.1.0
RISC-V (32-bits) gcc 13.2.0
RISC-V (32-bits) gcc 8.2.0
RISC-V (32-bits) gcc 8.5.0
RISC-V (32-bits) gcc 9.4.0
RISC-V (64-bits) gcc (trunk)
RISC-V (64-bits) gcc 10.2.0
RISC-V (64-bits) gcc 10.3.0
RISC-V (64-bits) gcc 11.2.0
RISC-V (64-bits) gcc 11.3.0
RISC-V (64-bits) gcc 11.4.0
RISC-V (64-bits) gcc 12.1.0
RISC-V (64-bits) gcc 12.2.0
RISC-V (64-bits) gcc 12.3.0
RISC-V (64-bits) gcc 13.1.0
RISC-V (64-bits) gcc 13.2.0
RISC-V (64-bits) gcc 8.2.0
RISC-V (64-bits) gcc 8.5.0
RISC-V (64-bits) gcc 9.4.0
RISC-V rv32gc clang (trunk)
RISC-V rv32gc clang 10.0.0
RISC-V rv32gc clang 10.0.1
RISC-V rv32gc clang 11.0.0
RISC-V rv32gc clang 11.0.1
RISC-V rv32gc clang 12.0.0
RISC-V rv32gc clang 12.0.1
RISC-V rv32gc clang 13.0.0
RISC-V rv32gc clang 13.0.1
RISC-V rv32gc clang 14.0.0
RISC-V rv32gc clang 15.0.0
RISC-V rv32gc clang 16.0.0
RISC-V rv32gc clang 17.0.1
RISC-V rv32gc clang 18.1.0
RISC-V rv32gc clang 9.0.0
RISC-V rv32gc clang 9.0.1
RISC-V rv64gc clang (trunk)
RISC-V rv64gc clang 10.0.0
RISC-V rv64gc clang 10.0.1
RISC-V rv64gc clang 11.0.0
RISC-V rv64gc clang 11.0.1
RISC-V rv64gc clang 12.0.0
RISC-V rv64gc clang 12.0.1
RISC-V rv64gc clang 13.0.0
RISC-V rv64gc clang 13.0.1
RISC-V rv64gc clang 14.0.0
RISC-V rv64gc clang 15.0.0
RISC-V rv64gc clang 16.0.0
RISC-V rv64gc clang 17.0.1
RISC-V rv64gc clang 18.1.0
RISC-V rv64gc clang 9.0.0
RISC-V rv64gc clang 9.0.1
Raspbian Buster
Raspbian Stretch
SPARC LEON gcc 12.2.0
SPARC LEON gcc 12.3.0
SPARC LEON gcc 13.1.0
SPARC LEON gcc 13.2.0
SPARC gcc 12.2.0
SPARC gcc 12.3.0
SPARC gcc 13.1.0
SPARC gcc 13.2.0
SPARC64 gcc 12.2.0
SPARC64 gcc 12.3.0
SPARC64 gcc 13.1.0
SPARC64 gcc 13.2.0
TI C6x gcc 12.2.0
TI C6x gcc 12.3.0
TI C6x gcc 13.1.0
TI C6x gcc 13.2.0
TI CL430 21.6.1
VAX gcc NetBSDELF 10.4.0
VAX gcc NetBSDELF 10.5.0 (Nov 15 03:50:22 2023)
WebAssembly clang (trunk)
Xtensa ESP32 gcc 11.2.0 (2022r1)
Xtensa ESP32 gcc 12.2.0 (20230208)
Xtensa ESP32 gcc 8.2.0 (2019r2)
Xtensa ESP32 gcc 8.2.0 (2020r1)
Xtensa ESP32 gcc 8.2.0 (2020r2)
Xtensa ESP32 gcc 8.4.0 (2020r3)
Xtensa ESP32 gcc 8.4.0 (2021r1)
Xtensa ESP32 gcc 8.4.0 (2021r2)
Xtensa ESP32-S2 gcc 11.2.0 (2022r1)
Xtensa ESP32-S2 gcc 12.2.0 (20230208)
Xtensa ESP32-S2 gcc 8.2.0 (2019r2)
Xtensa ESP32-S2 gcc 8.2.0 (2020r1)
Xtensa ESP32-S2 gcc 8.2.0 (2020r2)
Xtensa ESP32-S2 gcc 8.4.0 (2020r3)
Xtensa ESP32-S2 gcc 8.4.0 (2021r1)
Xtensa ESP32-S2 gcc 8.4.0 (2021r2)
Xtensa ESP32-S3 gcc 11.2.0 (2022r1)
Xtensa ESP32-S3 gcc 12.2.0 (20230208)
Xtensa ESP32-S3 gcc 8.4.0 (2020r3)
Xtensa ESP32-S3 gcc 8.4.0 (2021r1)
Xtensa ESP32-S3 gcc 8.4.0 (2021r2)
arm64 msvc v19.28 VS16.9
arm64 msvc v19.29 VS16.10
arm64 msvc v19.29 VS16.11
arm64 msvc v19.30
arm64 msvc v19.31
arm64 msvc v19.32
arm64 msvc v19.33
arm64 msvc v19.34
arm64 msvc v19.35
arm64 msvc v19.36
arm64 msvc v19.37
arm64 msvc v19.38
arm64 msvc v19.latest
armv7-a clang (trunk)
armv7-a clang 10.0.0
armv7-a clang 10.0.1
armv7-a clang 11.0.0
armv7-a clang 11.0.1
armv7-a clang 9.0.0
armv7-a clang 9.0.1
armv8-a clang (all architectural features, trunk)
armv8-a clang (trunk)
armv8-a clang 10.0.0
armv8-a clang 10.0.1
armv8-a clang 11.0.0
armv8-a clang 11.0.1
armv8-a clang 12.0.0
armv8-a clang 13.0.0
armv8-a clang 14.0.0
armv8-a clang 15.0.0
armv8-a clang 16.0.0
armv8-a clang 17.0.1
armv8-a clang 18.1.0
armv8-a clang 9.0.0
armv8-a clang 9.0.1
ellcc 0.1.33
ellcc 0.1.34
ellcc 2017-07-16
hexagon-clang 16.0.5
llvm-mos atari2600-3e
llvm-mos atari2600-4k
llvm-mos atari2600-common
llvm-mos atari5200-supercart
llvm-mos atari8-cart-megacart
llvm-mos atari8-cart-std
llvm-mos atari8-cart-xegs
llvm-mos atari8-common
llvm-mos atari8-dos
llvm-mos c128
llvm-mos c64
llvm-mos commodore
llvm-mos cpm65
llvm-mos cx16
llvm-mos dodo
llvm-mos eater
llvm-mos mega65
llvm-mos nes
llvm-mos nes-action53
llvm-mos nes-cnrom
llvm-mos nes-gtrom
llvm-mos nes-mmc1
llvm-mos nes-mmc3
llvm-mos nes-nrom
llvm-mos nes-unrom
llvm-mos nes-unrom-512
llvm-mos osi-c1p
llvm-mos pce
llvm-mos pce-cd
llvm-mos pce-common
llvm-mos pet
llvm-mos rp6502
llvm-mos rpc8e
llvm-mos supervision
llvm-mos vic20
loongarch64 gcc 12.2.0
loongarch64 gcc 12.3.0
loongarch64 gcc 13.1.0
loongarch64 gcc 13.2.0
mips clang 13.0.0
mips clang 14.0.0
mips clang 15.0.0
mips clang 16.0.0
mips clang 17.0.1
mips clang 18.1.0
mips gcc 11.2.0
mips gcc 12.1.0
mips gcc 12.2.0
mips gcc 12.3.0
mips gcc 13.1.0
mips gcc 13.2.0
mips gcc 4.9.4
mips gcc 5.4
mips gcc 5.5.0
mips gcc 9.3.0 (codescape)
mips gcc 9.5.0
mips64 (el) gcc 12.1.0
mips64 (el) gcc 12.2.0
mips64 (el) gcc 12.3.0
mips64 (el) gcc 13.1.0
mips64 (el) gcc 13.2.0
mips64 (el) gcc 4.9.4
mips64 (el) gcc 5.4.0
mips64 (el) gcc 5.5.0
mips64 (el) gcc 9.5.0
mips64 clang 13.0.0
mips64 clang 14.0.0
mips64 clang 15.0.0
mips64 clang 16.0.0
mips64 clang 17.0.1
mips64 clang 18.1.0
mips64 gcc 11.2.0
mips64 gcc 12.1.0
mips64 gcc 12.2.0
mips64 gcc 12.3.0
mips64 gcc 13.1.0
mips64 gcc 13.2.0
mips64 gcc 4.9.4
mips64 gcc 5.4.0
mips64 gcc 5.5.0
mips64 gcc 9.5.0
mips64el clang 13.0.0
mips64el clang 14.0.0
mips64el clang 15.0.0
mips64el clang 16.0.0
mips64el clang 17.0.1
mips64el clang 18.1.0
mipsel clang 13.0.0
mipsel clang 14.0.0
mipsel clang 15.0.0
mipsel clang 16.0.0
mipsel clang 17.0.1
mipsel clang 18.1.0
mipsel gcc 12.1.0
mipsel gcc 12.2.0
mipsel gcc 12.3.0
mipsel gcc 13.1.0
mipsel gcc 13.2.0
mipsel gcc 4.9.4
mipsel gcc 5.4.0
mipsel gcc 5.5.0
mipsel gcc 9.5.0
nanoMIPS gcc 6.3.0 (mtk)
power gcc 11.2.0
power gcc 12.1.0
power gcc 12.2.0
power gcc 12.3.0
power gcc 13.1.0
power gcc 13.2.0
power gcc 4.8.5
power64 AT12.0 (gcc8)
power64 AT13.0 (gcc9)
power64 gcc 11.2.0
power64 gcc 12.1.0
power64 gcc 12.2.0
power64 gcc 12.3.0
power64 gcc 13.1.0
power64 gcc 13.2.0
power64 gcc trunk
power64le AT12.0 (gcc8)
power64le AT13.0 (gcc9)
power64le clang (trunk)
power64le gcc 11.2.0
power64le gcc 12.1.0
power64le gcc 12.2.0
power64le gcc 12.3.0
power64le gcc 13.1.0
power64le gcc 13.2.0
power64le gcc 6.3.0
power64le gcc trunk
powerpc64 clang (trunk)
s390x gcc 11.2.0
s390x gcc 12.1.0
s390x gcc 12.2.0
s390x gcc 12.3.0
s390x gcc 13.1.0
s390x gcc 13.2.0
sh gcc 12.2.0
sh gcc 12.3.0
sh gcc 13.1.0
sh gcc 13.2.0
sh gcc 4.9.4
sh gcc 9.5.0
vast (trunk)
x64 msvc v19.0 (WINE)
x64 msvc v19.10 (WINE)
x64 msvc v19.14
x64 msvc v19.14 (WINE)
x64 msvc v19.15
x64 msvc v19.16
x64 msvc v19.20
x64 msvc v19.21
x64 msvc v19.22
x64 msvc v19.23
x64 msvc v19.24
x64 msvc v19.25
x64 msvc v19.26
x64 msvc v19.27
x64 msvc v19.28
x64 msvc v19.28 VS16.9
x64 msvc v19.29 VS16.10
x64 msvc v19.29 VS16.11
x64 msvc v19.30
x64 msvc v19.31
x64 msvc v19.32
x64 msvc v19.33
x64 msvc v19.34
x64 msvc v19.35
x64 msvc v19.36
x64 msvc v19.37
x64 msvc v19.38
x64 msvc v19.latest
x86 djgpp 4.9.4
x86 djgpp 5.5.0
x86 djgpp 6.4.0
x86 djgpp 7.2.0
x86 msvc v19.0 (WINE)
x86 msvc v19.10 (WINE)
x86 msvc v19.14
x86 msvc v19.14 (WINE)
x86 msvc v19.15
x86 msvc v19.16
x86 msvc v19.20
x86 msvc v19.21
x86 msvc v19.22
x86 msvc v19.23
x86 msvc v19.24
x86 msvc v19.25
x86 msvc v19.26
x86 msvc v19.27
x86 msvc v19.28
x86 msvc v19.28 VS16.9
x86 msvc v19.29 VS16.10
x86 msvc v19.29 VS16.11
x86 msvc v19.30
x86 msvc v19.31
x86 msvc v19.32
x86 msvc v19.33
x86 msvc v19.34
x86 msvc v19.35
x86 msvc v19.36
x86 msvc v19.37
x86 msvc v19.38
x86 msvc v19.latest
x86 nvc++ 22.11
x86 nvc++ 22.7
x86 nvc++ 22.9
x86 nvc++ 23.1
x86 nvc++ 23.11
x86 nvc++ 23.3
x86 nvc++ 23.5
x86 nvc++ 23.7
x86 nvc++ 23.9
x86 nvc++ 24.1
x86 nvc++ 24.3
x86-64 Zapcc 190308
x86-64 clang (amd-stg-open)
x86-64 clang (assertions trunk)
x86-64 clang (clangir)
x86-64 clang (experimental -Wlifetime)
x86-64 clang (experimental P1061)
x86-64 clang (experimental P1144)
x86-64 clang (experimental P1221)
x86-64 clang (experimental P2996)
x86-64 clang (experimental metaprogramming - P2632)
x86-64 clang (experimental pattern matching)
x86-64 clang (old concepts branch)
x86-64 clang (reflection)
x86-64 clang (resugar)
x86-64 clang (thephd.dev)
x86-64 clang (trunk)
x86-64 clang (variadic friends - P2893)
x86-64 clang (widberg)
x86-64 clang 10.0.0
x86-64 clang 10.0.0 (assertions)
x86-64 clang 10.0.1
x86-64 clang 11.0.0
x86-64 clang 11.0.0 (assertions)
x86-64 clang 11.0.1
x86-64 clang 12.0.0
x86-64 clang 12.0.0 (assertions)
x86-64 clang 12.0.1
x86-64 clang 13.0.0
x86-64 clang 13.0.0 (assertions)
x86-64 clang 13.0.1
x86-64 clang 14.0.0
x86-64 clang 14.0.0 (assertions)
x86-64 clang 15.0.0
x86-64 clang 15.0.0 (assertions)
x86-64 clang 16.0.0
x86-64 clang 16.0.0 (assertions)
x86-64 clang 17.0.1
x86-64 clang 17.0.1 (assertions)
x86-64 clang 18.1.0
x86-64 clang 18.1.0 (assertions)
x86-64 clang 2.6.0 (assertions)
x86-64 clang 2.7.0 (assertions)
x86-64 clang 2.8.0 (assertions)
x86-64 clang 2.9.0 (assertions)
x86-64 clang 3.0.0
x86-64 clang 3.0.0 (assertions)
x86-64 clang 3.1
x86-64 clang 3.1 (assertions)
x86-64 clang 3.2
x86-64 clang 3.2 (assertions)
x86-64 clang 3.3
x86-64 clang 3.3 (assertions)
x86-64 clang 3.4 (assertions)
x86-64 clang 3.4.1
x86-64 clang 3.5
x86-64 clang 3.5 (assertions)
x86-64 clang 3.5.1
x86-64 clang 3.5.2
x86-64 clang 3.6
x86-64 clang 3.6 (assertions)
x86-64 clang 3.7
x86-64 clang 3.7 (assertions)
x86-64 clang 3.7.1
x86-64 clang 3.8
x86-64 clang 3.8 (assertions)
x86-64 clang 3.8.1
x86-64 clang 3.9.0
x86-64 clang 3.9.0 (assertions)
x86-64 clang 3.9.1
x86-64 clang 4.0.0
x86-64 clang 4.0.0 (assertions)
x86-64 clang 4.0.1
x86-64 clang 5.0.0
x86-64 clang 5.0.0 (assertions)
x86-64 clang 5.0.1
x86-64 clang 5.0.2
x86-64 clang 6.0.0
x86-64 clang 6.0.0 (assertions)
x86-64 clang 6.0.1
x86-64 clang 7.0.0
x86-64 clang 7.0.0 (assertions)
x86-64 clang 7.0.1
x86-64 clang 7.1.0
x86-64 clang 8.0.0
x86-64 clang 8.0.0 (assertions)
x86-64 clang 8.0.1
x86-64 clang 9.0.0
x86-64 clang 9.0.0 (assertions)
x86-64 clang 9.0.1
x86-64 clang rocm-4.5.2
x86-64 clang rocm-5.0.2
x86-64 clang rocm-5.1.3
x86-64 clang rocm-5.2.3
x86-64 clang rocm-5.3.3
x86-64 clang rocm-5.7.0
x86-64 gcc (contract labels)
x86-64 gcc (contracts natural syntax)
x86-64 gcc (contracts)
x86-64 gcc (coroutines)
x86-64 gcc (modules)
x86-64 gcc (trunk)
x86-64 gcc 10.1
x86-64 gcc 10.2
x86-64 gcc 10.3
x86-64 gcc 10.4
x86-64 gcc 10.5
x86-64 gcc 11.1
x86-64 gcc 11.2
x86-64 gcc 11.3
x86-64 gcc 11.4
x86-64 gcc 12.1
x86-64 gcc 12.2
x86-64 gcc 12.3
x86-64 gcc 13.1
x86-64 gcc 13.2
x86-64 gcc 4.1.2
x86-64 gcc 4.4.7
x86-64 gcc 4.5.3
x86-64 gcc 4.6.4
x86-64 gcc 4.7.1
x86-64 gcc 4.7.2
x86-64 gcc 4.7.3
x86-64 gcc 4.7.4
x86-64 gcc 4.8.1
x86-64 gcc 4.8.2
x86-64 gcc 4.8.3
x86-64 gcc 4.8.4
x86-64 gcc 4.8.5
x86-64 gcc 4.9.0
x86-64 gcc 4.9.1
x86-64 gcc 4.9.2
x86-64 gcc 4.9.3
x86-64 gcc 4.9.4
x86-64 gcc 5.1
x86-64 gcc 5.2
x86-64 gcc 5.3
x86-64 gcc 5.4
x86-64 gcc 5.5
x86-64 gcc 6.1
x86-64 gcc 6.2
x86-64 gcc 6.3
x86-64 gcc 6.4
x86-64 gcc 7.1
x86-64 gcc 7.2
x86-64 gcc 7.3
x86-64 gcc 7.4
x86-64 gcc 7.5
x86-64 gcc 8.1
x86-64 gcc 8.2
x86-64 gcc 8.3
x86-64 gcc 8.4
x86-64 gcc 8.5
x86-64 gcc 9.1
x86-64 gcc 9.2
x86-64 gcc 9.3
x86-64 gcc 9.4
x86-64 gcc 9.5
x86-64 icc 13.0.1
x86-64 icc 16.0.3
x86-64 icc 17.0.0
x86-64 icc 18.0.0
x86-64 icc 19.0.0
x86-64 icc 19.0.1
x86-64 icc 2021.1.2
x86-64 icc 2021.10.0
x86-64 icc 2021.2.0
x86-64 icc 2021.3.0
x86-64 icc 2021.4.0
x86-64 icc 2021.5.0
x86-64 icc 2021.6.0
x86-64 icc 2021.7.0
x86-64 icc 2021.7.1
x86-64 icc 2021.8.0
x86-64 icc 2021.9.0
x86-64 icx (latest)
x86-64 icx 2021.1.2
x86-64 icx 2021.2.0
x86-64 icx 2021.3.0
x86-64 icx 2021.4.0
x86-64 icx 2022.0.0
x86-64 icx 2022.1.0
x86-64 icx 2022.2.0
x86-64 icx 2022.2.1
x86-64 icx 2023.0.0
x86-64 icx 2023.1.0
x86-64 icx 2023.2.1
x86-64 icx 2024.0.0
zig c++ 0.10.0
zig c++ 0.11.0
zig c++ 0.12.0
zig c++ 0.6.0
zig c++ 0.7.0
zig c++ 0.7.1
zig c++ 0.8.0
zig c++ 0.9.0
zig c++ trunk
Options
Source code
#include <iostream> #include <chrono> #include <string> namespace single_threaded_memory_pool_ { // reference: 《提高C++性能的编程技术》:第六章:单线程内存池 class Rational1 { public: Rational1(int a = 0, int b = 1) : n(a), d(b) {} private: int n; // 分子 int d; // 分母 }; // class Rational1 // 专用Rational2内存管理器 // 为避免频繁地使用内存管理器,Rational2类要维护一个预分配的Rational2对象的静态连接列表,该列表列出空闲的可用对象. // 当需要Rational2对象时,可以从空闲列表中取出一个,使用后再把它放回空闲列表以便今后分配. // 声明一个辅助结构来连接空闲列表的相邻元素 class NextOnFreeList { public: NextOnFreeList* next; }; // class NextOnFreeList // 空闲列表被声明为一个由NextOnFreeList元素组成的列表 class Rational2 { public: Rational2(int a = 0, int b = 1) : n(a),d(b) {} inline void* operator new(size_t size); inline void operator delete(void* doomed, size_t size); static void newMemPool() { expandTheFreeList(); } static void deleteMemPool(); private: static NextOnFreeList* freeList; // Rational2对象的空闲列表 static void expandTheFreeList(); enum { EXPANSION_SIZE = 32}; int n; // 分子 int d; // 分母 }; // class Rational2 NextOnFreeList* Rational2::freeList = nullptr; // new()在空闲列表中分配一个Rational2对象.如果列表为空,则扩展列表 inline void* Rational2::operator new(size_t size) { if (nullptr == freeList) { // 如果列表为空,则将其填满 expandTheFreeList(); } NextOnFreeList* head = freeList; freeList = head->next; return head; } // delete()把Rational2对象直接添加到空闲列表的头部,以返回Rational2对象 inline void Rational2::operator delete(void* doomed, size_t size) { NextOnFreeList* head = static_cast<NextOnFreeList*>(doomed); head->next = freeList; freeList = head; } // 当空闲列表用完后,需要从堆上分配更多的Rational2对象. // Rational2和NextOnFreeList之间的类型转换是有危险的,必须确保空闲列表的元素足够大以支持任意一种类型 // 当我们用Rational2对象填充空闲列表时,要记得比较Rational2和NextOnFreeList的大小,并且分配较大的那一个 void Rational2::expandTheFreeList() { // 本质上,expandTheFreeList的实现并不是最优的.因为空闲列表中每增加一个元素,就调用一次new. 如果只调用一次new // 获得一大块内存,然后把它切分给多个元素,这样会更高效。孤立地看,这种想法很正确。然而我们创建内存管理器时, // 认为它不会频繁扩展和收缩,否则必须重新查看代码实现并修正它 // 我们必须分配足够大的对象以包含下一个指针 size_t size = sizeof(Rational2) > sizeof(NextOnFreeList*) ? sizeof(Rational2) : sizeof(NextOnFreeList*); NextOnFreeList* runner = static_cast<NextOnFreeList*>((void*)new char[size]); freeList = runner; for (int i = 0; i < EXPANSION_SIZE; ++i) { runner->next = static_cast<NextOnFreeList*>((void*)new char[size]); runner = runner->next; } runner->next = nullptr; } void Rational2::deleteMemPool() { NextOnFreeList* nextPtr; for (nextPtr = freeList; nextPtr != nullptr; nextPtr = freeList) { freeList = freeList->next; delete [] nextPtr; } } /// // 固定大小对象的内存池: 观察Rational2内存管理器的实现,会很清楚地发现内存管理逻辑实际上独立于特定的Rational2类. // 它唯一依赖的是类对象的大小----这正是用模板实现内存池的原因 template<class T> class MemoryPool1 { public: MemoryPool1(size_t size = EXPANSION_SIZE); ~MemoryPool1(); // 从空闲列表中分配T元素 inline void* alloc(size_t size); // 返回T元素到空闲列表中 inline void free(void* someElement); private: // 空闲列表的下一元素 MemoryPool1<T>* next; // 如果空闲列表为空,按该大小扩展它 enum { EXPANSION_SIZE = 32 }; // 添加空闲元素至空闲列表 void expandTheFreeList(int howMany = EXPANSION_SIZE); }; // 构造函数初始化空闲列表,参数size指定空闲列表的初始化长度 template<class T> MemoryPool1<T>::MemoryPool1(size_t size) { expandTheFreeList(size); } // 析构函数遍历空闲列表并且删除所有元素 template<class T> MemoryPool1<T>::~MemoryPool1() { MemoryPool1<T>* nextPtr = next; for (nextPtr = next; nextPtr != nullptr; nextPtr = next) { next = next->next; delete [] static_cast<char*>(static_cast<void*>(nextPtr)); } } // alloc函数为T元素分配足够大的空间,如果空闲列表用尽,则调用expandThrFreeList函数来扩充它 template<class T> inline void* MemoryPool1<T>::alloc(size_t size) { if (!next) { expandTheFreeList(); } MemoryPool1<T>* head = next; next = head->next; return head; } // free函数把T元素放回空闲列表,以此来释放它 template<class T> inline void MemoryPool1<T>::free(void* doomed) { MemoryPool1<T>* head = static_cast<MemoryPool1<T>*>(doomed); head->next = next; next = head; } // expandTheFreeList函数用来向空闲列表添加新元素,首先从堆上分配新元素,然后把它们连接到列表中 // 该函数在空闲列表用尽时被调用 template<class T> void MemoryPool1<T>::expandTheFreeList(int howMany) { // 必须分配足够大的对象以包含下一个指针 size_t size = sizeof(T) > sizeof(MemoryPool1<T>*) ? sizeof(T) : sizeof(MemoryPool1<T>*); MemoryPool1<T>* runner = static_cast<MemoryPool1<T>*>((void*)(new char[size])); next = runner; for (int i = 0; i < howMany; ++i) { runner->next = static_cast<MemoryPool1<T>*>((void*)(new char[size])); runner = runner->next; } runner->next = nullptr; } // Rational3类不再需要维护它自己的空闲列表,这项任务委托给了MemoryPool1类 class Rational3 { public: Rational3(int a = 0, int b = 1) : n(a),d(b) {} void* operator new(size_t size) { return memPool->alloc(size); } void operator delete(void* doomed, size_t size) { memPool->free(doomed); } static void newMemPool() { memPool = new MemoryPool1<Rational3>; } static void deleteMemPool() { delete memPool; } private: int n; // 分子 int d; // 分母 static MemoryPool1<Rational3>* memPool; }; MemoryPool1<Rational3>* Rational3::memPool = nullptr; // 单线程可变大小内存管理器: // MemoryChunk类取代之前版本中使用的NextOnFreeList类,它用来把不同大小的内存块连接起来形成块序列 class MemoryChunk { public: MemoryChunk(MemoryChunk* nextChunk, size_t chunkSize); // 析构函数释放构造函数获得的内存空间 ~MemoryChunk() { delete [] mem; } inline void* alloc(size_t size); inline void free(void* someElement); // 指向列表下一内存块的指针 MemoryChunk* nextMemChunk() { return next; } // 当前内存块剩余空间大小 size_t spaceAvailable() { return chunkSize - bytesAlreadyAllocated; } // 这是一个内存块的默认大小 enum { DEFAULT_CHUNK_SIZE = 4096 }; private: MemoryChunk* next; void* mem; // 一个内存块的默认大小 size_t chunkSize; // 当前内存块中已分配的字节数 size_t bytesAlreadyAllocated; }; // 构造函数首先确定内存块的适当大小,然后根据这个大小从堆上分配私有存储空间 // MemoryChunk将next成员指向输入参数nextChunk, nextChunk是列表先前的头部 MemoryChunk::MemoryChunk(MemoryChunk* nextChunk, size_t reqSize) { chunkSize = (reqSize > DEFAULT_CHUNK_SIZE) ? reqSize : DEFAULT_CHUNK_SIZE; next = nextChunk; bytesAlreadyAllocated = 0; mem = (void*)(new char[chunkSize]); } // alloc函数处理内存分配请求,它返回一个指针,该指针指向mem所指向的MemoryChunk私有存储空间中的可用空间。 // 该函数通过更新该块中已分配的字节数来记录可用空间的大小 void* MemoryChunk::alloc(size_t requestSize) { void* addr = static_cast<void*>(static_cast<char*>(mem) + bytesAlreadyAllocated); bytesAlreadyAllocated += requestSize; return addr; } // 在该实现中,不用担心空闲内存段的释放。当对象被删除后,整个内存块将被释放并且返回到堆上 inline void MemoryChunk::free(void* doomed) { } // MemoryChunk只是一个辅助类,ByteMemoryPoll类用它来实现可变大小的内存管理 class ByteMemoryPool { public: ByteMemoryPool(size_t initSize = MemoryChunk::DEFAULT_CHUNK_SIZE); ~ByteMemoryPool(); // 从私有内存池分配内存 inline void* alloc(size_t size); // 释放先前从内存池中分配的内存 inline void free(void* someElement); private: // 内存块列表,它是我们的私有存储空间 MemoryChunk* listOfMemoryChunks = nullptr; // 向我们的私有存储空间添加一个内存块 void expandStorage(size_t reqSize); }; // 虽然内存块列表可能包含多个块,但只有第一块拥有可用于分配的内存。其它块表示已分配的内存。 // 列表的首个元素是唯一能够分配可以内存的块。 // 构造函数接收initSize参数来设定一个内存块的大小,即构造函数借此来设置单个内存块的大小。 // expandStorage方法使listOfMemoryChunks指向一个已分配的MemoryChunk对象 // 创建ByteMemoryPool对象,生成私有存储空间 ByteMemoryPool::ByteMemoryPool(size_t initSize) { expandStorage(initSize); } // 析构函数遍历内存块列表并且删除它们 ByteMemoryPool::~ByteMemoryPool() { MemoryChunk* memChunk = listOfMemoryChunks; while (memChunk) { listOfMemoryChunks = memChunk->nextMemChunk(); delete memChunk; memChunk = listOfMemoryChunks; } } // alloc函数确保有足够的可用空间,而把分配任务托付给列表头的MemoryChunk void* ByteMemoryPool::alloc(size_t requestSize) { size_t space = listOfMemoryChunks->spaceAvailable(); if (space < requestSize) { expandStorage(requestSize); } return listOfMemoryChunks->alloc(requestSize); } // 释放之前分配的内存的任务被委派给列表头部的MemoryChunk来完成 // MemoryChunk::free不做任何事情,因为ByteMemoryPool的实现不会重用之前分配的内存。如果需要更多内存, // 我们将创建新的内存块以便今后分配使用。在内存池被销毁时,内存释放回堆中。ByteMemoryPool析构函数 // 释放所有的内存块到堆中 inline void ByteMemoryPool::free(void* doomed) { listOfMemoryChunks->free(doomed); } // 若遇到内存块用尽这种不太可能的情况,我们通过创建新的内存块并把它添加到内存块列表的头部来扩展它 void ByteMemoryPool::expandStorage(size_t reqSize) { listOfMemoryChunks = new MemoryChunk(listOfMemoryChunks, reqSize); } class Rational4 { public: Rational4(int a = 0, int b = 1) : n(a),d(b) {} void* operator new(size_t size) { return memPool->alloc(size); } void operator delete(void* doomed, size_t size) { memPool->free(doomed); } static void newMemPool() { memPool = new ByteMemoryPool; } static void deleteMemPool() { delete memPool; } private: int n; // 分子 int d; // 分母 static ByteMemoryPool* memPool; }; } // namespace single_threaded_memory_pool_ using namespace single_threaded_memory_pool_; ByteMemoryPool* Rational4::memPool = nullptr; int main() { using namespace std::chrono; high_resolution_clock::time_point time_start, time_end; const int cycle_number1{10000}, cycle_number2{1000}; { // 测试全局函数new()和delete()的基准性能 Rational1* array[cycle_number2]; time_start = high_resolution_clock::now(); for (int j =0; j < cycle_number1; ++j) { for (int i =0; i < cycle_number2; ++i) { array[i] = new Rational1(i); } for (int i = 0; i < cycle_number2; ++i) { delete array[i]; } } time_end = high_resolution_clock::now(); fprintf(stdout, "global function new/delete time spend: %f seconds\n",(duration_cast<duration<double>>(time_end - time_start)).count()); } { // 专用Rational2内存管理器测试 Rational2* array[cycle_number2]; time_start = high_resolution_clock::now(); Rational2::newMemPool(); for (int j = 0; j < cycle_number1; ++j) { for (int i = 0; i < cycle_number2; ++i) { array[i] = new Rational2(i); } for (int i = 0; i < cycle_number2; ++i) { delete array[i]; } } Rational2::deleteMemPool(); time_end = high_resolution_clock::now(); fprintf(stdout, "specialized rational2 memory manager time spend: %f seconds\n",(duration_cast<duration<double>>(time_end - time_start)).count()); } { // 固定大小对象的内存池测试 Rational3* array[cycle_number2]; time_start = high_resolution_clock::now(); Rational3::newMemPool(); for (int j = 0; j < cycle_number1; ++j) { for (int i = 0; i < cycle_number2; ++i) { array[i] = new Rational3(i); } for (int i = 0; i < cycle_number2; ++i) { delete array[i]; } } Rational3::deleteMemPool(); time_end = high_resolution_clock::now(); fprintf(stdout, "fixed-size object memory pool time spend: %f seconds\n",(duration_cast<duration<double>>(time_end - time_start)).count()); } { // 单线程可变大小内存管理器测试 Rational4* array[cycle_number2]; time_start = high_resolution_clock::now(); Rational4::newMemPool(); for (int j = 0; j < cycle_number1; ++j) { for (int i = 0; i < cycle_number2; ++i) { array[i] = new Rational4(i); } for (int i = 0; i < cycle_number2; ++i) { delete array[i]; } } Rational4::deleteMemPool(); time_end = high_resolution_clock::now(); fprintf(stdout, "single-threaded variable-size memory manager time spend: %f seconds\n",(duration_cast<duration<double>>(time_end - time_start)).count()); } return 0; }
Become a Patron
Sponsor on GitHub
Donate via PayPal
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
About the author
Statistics
Changelog
Version tree