[toc]

C++

Solution and Project

  • Solution is a vessel containing projects, and the code is the actual organizational unit of the project.

  • Solution is used to organize and manage multiple projects, while a project is used for real operations and construction.

hello_world

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>		//Pre-process
#if 1 //Pre-process can be an annotation


// The "static" keyword means that the function is only declared within this translation unit.
static void log()
{
std::cout << "hello World" << std::endl;

}


int main() //Entry ponit
{
std::cout << "hello World" << std::endl;
std::cin.get(); //It seems like the C function `getchar()`.
return 0;
}
#endif
  • cin、cout,Corresponding to the standard input stream and the standard output stream
  • std::cout << "hello World" << std::endl;can be considered asstd::cout.print("hello world").print("\n");

variable

  • The sizeof() function returns the size of variables.
  • If we define a float, we must add ‘f’ behind the variable, such as 0.3f. Otherwise, it will be recognized as a double variable.

head file

0x0

The difference between "" and <<>>:

Angle brackets are only used by the compiler to include paths. Quotes can do anything, but they are usually used for relative paths.

We have two ways to ensure that a header file is included only once:

0x1

#pragma once means only include this header file once.

0x2

1
2
3
4
#ifndef FunctionA
#define FunctionA
void FunctionA();
#endif

* and &

  • A pointer is an object in its own right.

  • A pointer need not be initialized at the time it is defined.

1
void* ptr = nullptr;		//pointer in C++11
  • A Reference Is an Alias.A reference is not an object. Instead, a reference is just another name for an already existing object.
  • A reference must be initialized.
1
2
3
4
5
6
7
8
9
10
void Function(int& value)
{
value ++;
}
int main()
{
int a = 10;
Function(a);
}
//Passing arguments by reference.

static

  • Use the prefix s_ to denote a static variable
  • static functions and global variables are accessible only from within the translation unit.
  • A static local variable persists after the function exits.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

#include <iostream>


void Function()
{
static int i = 0;
i++;
std::cout << i << std::endl;


}


int main()
{
Function();

Function();
Function();
Function();
Function();
std::cin.get();

}




  • A static class variable or method can have only one instance.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>

struct Entity
{
static int x, y;

static void Print()
{
std::cout << x << ", " << y << std::endl;
}


};

int Entity::x;
int Entity::y;


int main() {
Entity e;
Entity::x = 2; //e.x = 2;
Entity::y = 3; //e.y = 3;

Entity e1;
Entity::x = 5; //e1.x = 5;
Entity::y = 8; //e1.y = 8;

Entity::Print(); //e.Print();
Entity::Print(); //e1.Print();
}
  • Requires the variable to survive the function exit: Use static to decorate a local variable.

  • You need to scope the variable to the current file: static decorates a global variable.

  • Member variables/functions need to be called in case of shared variables or functions: static modifies member variables/functions.

extern

  • extern can be used to decorate a variable or function when you need to import a non-static variable or function from an external file.

->

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <string>

struct Vector3
{
double x, y, z;
};

int main() {
int offset = (int)&((Vector3*)0)->z; //0+16
std::cout << offset << std::endl; //16
offset = (int)&((Vector3*)1000)->z; //1000+16
std::cout << offset << std::endl; //1016
std::cin.get();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <string>
class Entity
{
private:
int x;
public:
void Print() const { std::cout << "hello" << std::endl; }

};

class ScopedPtr
{
private:
Entity* m_obj;
public:
ScopedPtr(Entity* entity)
:m_obj(entity)
{
}

~ScopedPtr()
{
delete m_obj;
}
Entity* operator->() //overload ->
{
return m_obj;
}
const Entity* operator->() const
{
return m_obj;
}

};



int main() {

ScopedPtr e = new Entity;
e->Print(); //different class

std::cin.get();
}

union

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<iostream>


#define print(x,y) std::cout<< x << ": "<< y << std::endl

struct vector2 {
int a, b;
};

struct vector4 {
union
{
struct {
int a, b, c, d;
};
struct {
vector2 A, B;
};
};
};

int main()
{
vector4 vector{1,2,3,4};

print("vector.A.a", vector.A.a);
print("vector.b", vector.A.b);
print("vector.B.a", vector.B.a);
print("vector.d", vector.d);
std::cin.get();
}
//vector.A.a: 1
//vector.b: 2
//vector.B.a: 3
//vector.d: 4

enum

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>

enum Example : unsigned char //typem, must be interger
{
A = 5, B, C //B = 6, C = 7
};



int main()
{
Example value = B;

if (value == 6)
{
std::cout << "hello" << std::endl;
}


std::cin.get();

}

linking

static linking && dynamic linking

1
2
3
4
5
6
7
8
9
10
#include <iostream>
//#include "GLFW/glfw3.h"

extern "C" int glfwInit();
//在C++中,函数名会被编译器修饰(或称为名称修饰),以便支持函数重载等特性。但是在C语言中,函数名不会被修饰。extern "C"的作用是告诉编译器,函数的名称应该按照C语言的规则处理,即不进行名称修饰。
int main()
{
int a = glfwInit();
std::cout << a<< std::endl;
}

使用 __declspec(dllimport) 导入到应用程序中 |Microsoft学习

//TODO

lib

//TODO

return

//TODO

macro

  • Can be used to manage release and Debug versions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <string>

#ifdef PR_DEBUG
#define Edition() std::cout << "Debug" << std::endl
#elif defined(PR_RELEASE)
#define Edition() std::cout << "Release" << std::endl
#endif


#if 0
function();
// Using 0 to control this function will not compile.
#endif

#define MAIN int main() { \
Edition(); \
std::cin.get(); \
}
MAIN //main function


//different output in different modes.

auto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<iostream>
#include<vector>
#include<string>
#include <unordered_map>
//unordered_map has less runtime than map, but it requires more space to maintain the hash.

class Device {};

class DevieManager
{
private:
std::unordered_map<std::string, std::vector<Device*>> m_Devices;
public:
const std::unordered_map<std::string, std::vector<Device*>>& GetDevices() const
{
return m_Devices;
}
};


int main()
{
std::vector<std::string> strings;
strings.push_back("Randolfluo");
strings.push_back("114514");
for (auto it = strings.begin(); it != strings.end(); it++)
{
std::cout << *it << std::endl;
}
DevieManager dm;
const auto& devices = dm.GetDevices();
std::cin.get();
}

function pointer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<iostream>
#include<vector>
void Print(int x)
{
std::cout << x << std::endl;
}

void forEach(const std::vector<int>& values, void(*func)(int))
{
for (int value : values)
func(value);
}
int main()
{
std::vector<int> values = { 1,2,3,4,5 }; //initializer lists
forEach(values, Print);
auto fun = Print; //void(*fun)(int x) //function pointer
fun(114514);
std::cin.get();

}

lambda

  • Lambdas allow us to define the methods of a function without the need for a function definition

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<functional>

    void Print(int x)
    {
    std::cout << x << std::endl;
    }

    void forEach(const std::vector<int>& values, const std::function<void(int)>& func)
    {
    for (int value : values)
    func(value);
    }
    int main()
    {
    std::vector<int> values = { 1,2,3,4,5 };
    auto it = std::find_if(values.begin(), values.end(), [](int value) {return value > 3; });
    Print(*it);

    auto lambda = [=](int value) { std::cout << value << std::endl; };
    forEach(values, lambda);

    std::cin.get();

    }

namespace

  • Namespaces can be used as additional information to distinguish functions, classes, variables, and so on with the same name from different libraries.

  • Use it in the smallest scope possible.

  • Make sure there are no conflicts with other namespaces
  • Never use in header files

multidimensional array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include<iostream>
#include <chrono>
#include <thread>

const int N = 30000;

class Timer {
private:
const char* m_Name;
public:
std::chrono::time_point < std::chrono::steady_clock> start,end;
std::chrono::duration<float> duration ;

Timer()
:m_Name("Unknown")
{
start = std::chrono::high_resolution_clock::now();
}
Timer(const char* name)
:m_Name(name)
{
start = std::chrono::high_resolution_clock::now();
}
~Timer()
{
end = std::chrono::high_resolution_clock::now();
duration = end - start;
auto duration1 = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << m_Name<< ":" << duration1 << std::endl;
}
};


void array2d_1()
{
Timer time("array2d_1");
int** a2d = new int* [N];
for (int i = 0; i < N; i++)
a2d[i] = new int[N];
//memory fragmentation
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
a2d[i][j] = 123;



for (int i = 0; i < N; i++)
delete[] a2d[i];
delete[] a2d;

}

void array2d_2()
{
Timer time("array2d_2");
int* array = new int[N * N];
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
array[i*N+j] = 123;

delete[] array;

}

int main()
{
array2d_1();
array2d_2();
std::cin.get();
}

//array2d_1:3027ms
//array2d_2:1762ms

type cast

  • static_cast
  • reinterpre_cast
  • dynamic_cast (Runtime type information)
  • const_cast

dynamic_castis specialized for pointer casting in inheritance hierarchies and must be a polymorphic class type (base class has vtable)

//TODO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<iostream>
#include<string>

class Entity
{
public:
virtual void Print() {};
};

class Player : public Entity
{
};

class Enemy : public Entity
{
};

int main()
{
Player* player = new Player();
Entity* actuallyEnemy = new Enemy();
Player* actuallyPlayer = player;

Player* p0 = dynamic_cast<Player*>(actuallyEnemy); //p0 = null
Player* p1 = dynamic_cast<Player*>(actuallyPlayer); //p1 = Player class address

}

explicit

\\TODO

templetes(generics)

  • The compiler writes code for you based on the rules you provide.

  • Template will never exist until we call it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <string>


template <typename T>

void Print(T value)
{
std::cout << value << std::endl;
}


template <typename T, int N>
class Array
{
private:
T m_Array[N];
public:
int GetSize() const {
return N;
}

};
int main() {
Array<int, 5> array;
std::cout << array.GetSize() << std::endl;

Print(123);
Print("Randolfluo");

std::cin.get();
}

Smart ptr

我们不能复制unique_ptr,因为free掉回产生空指针问题

unique_ptr

  • Unique_ptr deletes when over the scope.

  • We can’t copy unique_ptr,because when class free will generate null pointer.

shared_ptr

  • When the reference count equals zero, destruct the entity.

weak_ptr

  • weak_ptr can’t make reference count increase or decrease.
  • A weak_ptr cannot increase or decrease the reference count.

auto_ptr

  • (deprecated in C++11) (removed in C++17)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <string>
#include <memory>

class Entity
{
private:
int m_Num;
public:
Entity(int x)
:m_Num(x)
{
std::cout << "call Entity " << m_Num << std::endl;
}

~Entity()
{
std::cout << "destruct Entity " << m_Num << std::endl;
}

};

int main() {
{
std::shared_ptr<Entity> e0;
{
std::unique_ptr<Entity> entity = std::make_unique<Entity>(1); //call Entity 1

std::shared_ptr<Entity> sharedEntity = std::make_shared<Entity>(2); //call Entity 2
e0 = sharedEntity;
} //destruct Entity 1
} //destruct Entity 2
std::cin.get();
}