# Cpp review ## General concepts - inline function: reduce function call overhead - compiler & linker: source code -----> object file -----> executable file - C++ 11 - Auto - Lambda - for loop iterate - nullptr - override & final - new STL: forward_list, unordered_* ### 1. Operator | Operator | Associative | |:------|-----------:| | a++ | left -> right | | ++a, +a, ~a | **right -> left** | | *, /, % | left -> right | | +, - | left -> right | | <<, >> | left -> right | | >, <, >=, <= | left -> right | | =, +=, -= | **right -> left** | example ``` int a = 3, 2, 1; int arr[] = {10,20,30}; a > b > c = ? // 0 2*++a = ? // 6 ++a*2 = ? // 10 *arr+1 = ? // 11 ``` ### lvalue vs. rvalue ref: https://medium.com/@earth875/c-c-%E5%B8%B8%E8%A6%8B%E8%A9%A6%E9%A1%8C-961619b14f88 左值讓一段 expression 成為一個有名稱的物件;而右值只是一段 expression 的結果且隨時會蒸發不見。所以像 ++x 是左值而 x++ 卻是右值。 可以利用一個簡單的方法來 check 一段 expression 是 lvalue 或 rvalue,就是看看可不可以使用 & 運算元對該 expression 取得他的位置。 左值和右值皆可以為 non-const 和 const (用 non-const 似乎較 modifiable 來的直覺),以下為範例: <!-- string one("cute"); const string two("fluffy"); string three() { return "kittens"; } const string four() { return "are an essential part of a healthy diet"; } one; // modifiable lvalue two; // const lvalue three(); // modifiable rvalue four(); // const rvalue [以下待整理] --> Lvalue: 就是一個運算式後還保留其狀態的一個物件 就是Lvalue; 也 就是說 所有的變數(variables)包含nonmodifiable, const 的變數都是Lvalue. 這邊一個重點是 const的變數也是Lvalue Rvalue: 就是一個運算式過後其狀態就不會被保留了, 也就是一個暫存的數值 另一種說法(非完全正確, 但是可以依此來稍做判斷) 能出現在assignment 運算子(=)的左邊的稱為Lvalue, 而只能出現在右邊的稱為Rvalue 這邊只有說出現在左邊的是Lvalue, 但沒說Lvalue不能出現在右邊, 因此Lvalue在=運算子的左右兩邊都是被允許的, 而Rvalue是不能出現在左邊的; 這邊有沒有注意到, Lvalue是可以被放到右邊的, 也就是說Lvalue也可以被當作Rvalue, 但是Rvalue就不能被當作是Lvalue ### Memory - memory allocation global: global variable, visible by entire program stack: local var in a func, allocated by compiler, contiguous heap: random order - memory alignment k-Byte alignment k is the data memboer with most bytes ``` class A{ int aa; long double bb; char c; } A* a = new A(); sizeof(a) // 48 ``` - memory fragmentation ![](https://i.imgur.com/Z1eVS3F.png) ### Pointer - **Nonconstant** pointer to **constant** data e.g. arguments passed to a func ``` int a = 10, b = 15; const int* ptr = &a; ptr = &b; *ptr = 20; //error ``` - **Constant** pointer to **nonconstant** data e.g. array ``` int a[] = {10, 20 ,30}; ``` ### Static - static variable (global var) restricted in certain file - static variable (in function) ``` void foo(){ static int counter = 0; counter++; cout << "times " << counter << endl; } ``` - static member variable owned by all classes, - static member function access static member var ### extern internal linkage & external linkage ### const https://stackoverflow.com/questions/10716769/c-difference-between-const-positioning ### Class - Constructor is to “construct” (initialize) a class object, NOT to allocate the memory - copy constructor - declare myself (MyClass) as "friend” of other class (OtherClass) ``` class ListNode { friend class List; ... }; class List { void push_front(const T& d) { _head = new ListNode(d, _head); } ListNode* _head; }; ``` ### Inheritance https://www.cprogramming.com/tutorial/size_of_class_object.html - Virtual function is useful ONLY with polymorphism - Explicitly calling Base constructor - Define “virtual” Base destructor - destructor for derived class ### polymorphism - Program in general, execute in specific - virtual function + dynamic binding - about virtual: https://medium.com/theskyisblue/c-%E4%B8%AD%E9%97%9C%E6%96%BC-virtual-%E7%9A%84%E5%85%A9%E4%B8%89%E4%BA%8B-1b4e2a2dc373 - base class & derived class ``` class Base { public: virtual void pureVirutal() = 0; // only define interface virtual void virtualNonOverrided(); // interface & default imple virtual void virtualOverrided(); // polymorphism void nonVirtual(); }; class Derived: public Base { public: virtual void pureVirutal(); // must be overrided virtual void virtualOverrided(); void nonVirtual(); }; ``` Assign base-class ptr to derived class is safe, but only base class =: "is a" ``` int main(){ Derived d, d2; d.virtualNonOverrided(); // base d.virtualOverrided(); // derived d.nonVirtual(); // derived Base b = d2; // d2 "is a" base class object b.virtualNonOverrided(); // base b.virtualOverrided(); // base b.nonVirtual(); // base Base* b_ptr = new Derived(); b_ptr->virtualNonOverrided(); // base b_ptr->virtualOverrided(); // derived b_ptr->nonVirtual(); // base } ``` <!-- | base | derived | |:------|-----------:| | virutal | left -> right | | ++a, +a, ~a | **right -> left** | | *, /, % | left -> right | | +, - | left -> right | --> pure virtual: interface simple virtual: interface, implementation (default) dynamic binding, override non-virtual: interface, implementation <!-- ## Data structure ### set operation #### remove item for vector, list ``` for (it=c.begin(); it!=c.end(); ) { if (is need delete) it = c.erase(it); else it++; } ``` for set, map ``` for (it=c.begin(); it!=c.end(); ) { if (is need delete) c.erase(it++); else it++; } ``` --> - when to use virtual destructor ``` Base *b = new Derived(); // use b delete b; // Here's the problem! ``` Since Base's destructor is not virtual and b is a Base* pointing to a Derived object, delete b has undefined behaviour To sum up, always make base classes' destructors **virtual** when they're meant to be manipulated polymorphically. https://stackoverflow.com/questions/461203/when-to-use-virtual-destructors