Added map

This commit is contained in:
Polaris_Dane
2024-03-24 15:42:18 +08:00
parent 066b5db646
commit b48b580e1c
33 changed files with 4835 additions and 1 deletions

View File

@ -0,0 +1,81 @@
# How to Detect Memory Leak
## why memory leak?
申请的动态空间没有释放,即
* `new` 没有对应的 `delete`
* `malloc` 没有对应的 `free`
## How to detect?
### 一. Valgrind
#### 1.查看有没有装Valgrind
```bash
valgrind
```
```
valgrind --version
```
若已安装valgrind应显示
![](img/valgrind_exist0.png)
![](img/valgrind_exist1.png)
#### 2.安装Valgrind:
```bash
sudo apt install valgrind
```
另外还可以通过下载源码编译安装
源码地址https://valgrind.org/
下载源码:
```bash
wget https://sourceware.org/pub/valgrind/valgrind-3.20.0.tar.bz2
```
解压并安装:
```bash
tar -jxvf valgrind-3.20.0.tar.bz2
cd valgrind-3.20.0
./configure
make
sudo make install
```
安装后可以再次按照上面的步骤检查是否成功安装了valgrind
#### 3.开始使用
假设现在有一份有 memory leak 的代码如下:
```cpp
#include <stdlib.h>
void f(void)
{
int* x = malloc(10 * sizeof(int));
}
int main(void)
{
f();
return 0;
}
```
我们即可编译代码并使用valgrind检测
```bash
gcc -g test.c -o valgrind_test
valgrind --leak-check=yes ./valgrind_test
```
关于更多valgrind的使用方法可以参考官方文档https://valgrind.org/docs/manual/index.html
### 二. 使用 gcc 或 g++ 的 -fsanitize=leak 编译选项
g++ `-fsanitize` 编译选项其实已经提供了很多内存检测的功能,包括内存泄漏检测、内存访问越界检测等等,这些功能都是在编译时开启的。
常用的三个 `-fsanitize` 编译选项如下:
* `-fsanitize=address`:内存访问越界检测
* `-fsanitize=undefined`:未定义行为检测
* `-fsanitize=leak`:内存泄漏检测
有时我们需要更加详细的信息(比如:定位到错误在源代码中的位置)可以再加上 `-g` 选项。
对于同样的例子,我们使用 `-fsanitize=leak` 编译选项进行检测:
```bash
gcc test.c -o gcc_test -fsanitize=leak -g
./gcc_test
```
若检测出错误则会,显示如下信息:
![](img/gcc_test.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 934 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@ -0,0 +1,124 @@
# A Little Tutorial
这个文档对 C++ 11 中的 type_traits 做一个简短的介绍和实现指导。但主要还是需要同学们自学。
## What is traits in C++ 11
在 C++11 中traits 是指一组类型萃取机制type trait mechanism用于提取类型信息并根据这些信息在编译期间进行类型转换和编译期间的决策。它们在头文件 `type_traits` 中。
traits 通常使用**模板元编程**的技术实现,它允许我们在编译期间确定一个类型的属性,如是否是一个指针、是否是一个常量类型、是否是一个类等等。
我们给出若干个使用 C++ 11 type_traits 的代码实例:
```C++
#include <iostream>
#include <type_traits>
template<typename T>
void print_type(T x)
{
if (std::is_floating_point<T>::value)
std::cout << x << " is a floating point number.\n";
else
std::cout << x << " is not a floating point number.\n";
}
template<typename T, typename U>
void compare_types(T x, U y)
{
if (std::is_same<T, U>::value)
std::cout << x << " and "<< y << " have the same type.\n";
else
std::cout << x << " and "<< y << " have different type.\n";
}
struct A {}; // empty class
struct B { int x; }; // non-empty class
int main() {
std::cout << std::boolalpha;
std::cout << std::is_pointer<int>::value << std::endl; // 输出 false
std::cout << std::is_pointer<int*>::value << std::endl; // 输出 true
print_type(1.1451); // prints 1.1451 is a floating point number.
print_type(11451); // prints 11451 is not a floating point number.
compare_types(1.1451, 11451); // prints 1.1451 and 11451 have different types.
compare_types('a', 'b'); // prints a and b have the same type.
std::cout << std::boolalpha;
std::cout << "Is A an empty class? " << std::is_empty<A>::value << "\n"; // prints true
std::cout << "Is B an empty class? " << std::is_empty<B>::value << "\n"; // prints false
return 0;
}
```
以及traits自定义模板类的实现示例
```
// 定义数据 type 类
enum Type {
TYPE_1,
TYPE_2,
TYPE_3
}
// 自定义数据类型
class Foo {
public:
Type type = TYPE_1;
};
class Bar {
public:
Type type = TYPE_2;
};
// 定义type traits的模板类所有像这个模板类一样含有Type的类会被萃取出来进行模板化处理
template<typename T>
struct type_traits {
Type type = T::type;
}
// 内置数据类型同样可以进行这种萃取
template<typename int>
struct type_traits {
Type type = Type::TYPE_1;
}
template<typename double>
struct type_traits {
Type type = Type::TYPE_3;
}
// 萃取之后进行统一处理,写统一的编码函数
template<typename T>
void decode<const T& data, char* buf) {
if(type_traits<T>::type == Type::TYPE_1) {
...
}
else if(type_traits<T>::type == Type::TYPE_2) {
...
}
}
```
## Bonus
我们的 Bonus 可以是实现类似于 C++ 11 中的 type_traits 的某些功能,但是不要求完全一致。
这里举一个示例,我们以“迭代器可否被赋值特性”给出一个简单的实现思路:
```C++
//1.定义一个 type_traits 模板类
template<typename T>
struct my_type_traits{
using iterator_assignable = typename T::iterator_assignable;
};
//2.定义两个类,表示迭代器是否可被赋值的特性(这一步也可以使用枚举变量来实现)
struct my_true_type{
//todo
};
struct my_false_type{
//todo
};
//3.分别在可被赋值的迭代器和不可被赋值的迭代器中定义 iterator_assignable 类型
class iterator{
using iterator_assignable = my_true_type;
};
class const_iterator{
using iterator_assignable = my_false_type;
};
```
这部分我们不会提供提示数据,所以你需要自己设计测试代码,并且在 code review 时向助教展示。
如果想了解更多关于type traits可以参考 https://en.cppreference.com/w/cpp/header/type_traits或许其中的一些做法会给你一些思路的启发。
我们鼓励大家多去尝试,但不建议大家在这个作业中花费太多时间。