Added map
This commit is contained in:
81
map/tutorials/detect-memory-leak/detect-memory-leak.md
Normal file
81
map/tutorials/detect-memory-leak/detect-memory-leak.md
Normal 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应显示
|
||||
|
||||

|
||||
|
||||
或
|
||||
|
||||

|
||||
|
||||
#### 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
|
||||
```
|
||||
若检测出错误则会,显示如下信息:
|
||||

|
BIN
map/tutorials/detect-memory-leak/img/gcc_test.png
Normal file
BIN
map/tutorials/detect-memory-leak/img/gcc_test.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 934 KiB |
BIN
map/tutorials/detect-memory-leak/img/valgrind_exist0.png
Normal file
BIN
map/tutorials/detect-memory-leak/img/valgrind_exist0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 104 KiB |
BIN
map/tutorials/detect-memory-leak/img/valgrind_exist1.png
Normal file
BIN
map/tutorials/detect-memory-leak/img/valgrind_exist1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 82 KiB |
124
map/tutorials/type_traits/Tutorial.md
Normal file
124
map/tutorials/type_traits/Tutorial.md
Normal 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,或许其中的一些做法会给你一些思路的启发。
|
||||
|
||||
我们鼓励大家多去尝试,但不建议大家在这个作业中花费太多时间。
|
Reference in New Issue
Block a user