2017年2月24日 星期五

04 C++: C++ STL

04 C++: C++ STL

Algorithm vs member function

container member function vs algorithm
Any duplicated? Yes! But different.
List:
remove, unique, sort, merge, reverse
Associative:
count, find, lower_bound, upper_bound, equal_range
Unordered:
count, find, equal_range

Difference:
unordered_set.find() amortized constant time but std::find(t.begin(), t.end(), 1) linear time because no knowledge but iteratively. 

map.find() log n time but std::find(m.begin(), m.end(), pair(first, second)) take linear time and moreover it compare not only first but also second that makes double penalty. 

list.remove(1) and remove(l.begin(), l.end(), 1) looks same linear time but 
list.remove() is faster because removal uses redirecting the removed node pointers while std::remove() copy the elements behinds the removed node one by one as if the operation done on vector.

list.remove() reduce the size by 1 but i = std::remove() leaves the last element duplicated so needs extra l.erase(i, s.end());

list.sort() works but sort(l.begin(), l.end()) does not work because require random access iterator but list only has bidirectional iterator

Container member function preferred

Reverse Iterator

vector<int>::reverse_iterator r; r.rbegin();
Iterator can be converted to reverse iterator but in the opposite direction need to assign r.base() to iterator. r.base() return current iterator, where current iterator is the normal iterator off by one to the reverse iterator.

Vector insert erase invalidates all iterators and references to the vector

Equality vs equivalence

std::find(s.begin(), s.end(), 36) uses equality of equal operator, where set::find() uses equivalence !(x<y)&&!(y<x) .

Equality algo, use ==, no sort, list, vec
search, find_end, find_first_of, adjacent_search

Equivalence algo, use <, need sort, asso
binary_search, includes, lower_bound, upper_bound

STL removal
How to remove 1 from sequential vector v?
  1. Slow log(mn):
for (auto i=v.begin(); i!=v.end(); ) {
if (*i==1) i=v.erase(i); else ++i; }
  1. Wrong: remove(v.begin(), v.end(), 1);
  2. Correct log(n)
auto i =remove(v.begin(), v.end(), 1);
v.erase(i, v.end());
v.shrink_to_fit(); // or
vector<int>(c).swap(c);
Also called erase remove idiom

How to remove 1 from sequential list l?
  1. Slow by copy:
auto i = remove(l.begin(), l.end(), 1);
l.erase(i, l.end());
  1. Fast by reassigning pointers:
c.remove(1);

How to remove 1 from associative set?
  1. Slow by copy linear time:
auto i = remove(s.begin(), c.end(), 1);
c.erase(i, s.end());
  1. Fast by value log(n):
c.erase(1);

vector/deque: algorithm remove erase
list: member function remove
map: member function erase

STL iterator invalidation

For multiset s, simple for loop if *i equal 1 then s.erase(i) will crash because iterator i is invalidated after erase and so subsequent iterator compaison with c.end() will crash, as well as all containers after erase, so solution is to use s.erase(i++) if *i==1 so that iterator i will advance after erase and is valid because iterator after the erased element are still valid due to the tree structure of set.

For vector, v.erase(i++) does not work because after removal the iterator i pointing to the rest elements after erased one are all invalidated, and so the pointer, and so solution is i = v.erase(i)

How to use remove_if for vector?
bool equal(int i, int v) {return i==v;}
v.erase(remove_if(v.begin(), v.end(), bind(equal, placeholders::_1, 99)), v.end());
Or use lamba [](int i){return i==v;}

vector vs deque
Vector capacity grows exponentially 1248163264 for factor 2, some factor 1.5. Drawback is difficult contiguous memory reallocation when memory fragmented, along with data copying with expensive construction and destruction.
vector<C> v(6);// call default ctor 6 times
v.resize(7); // also call default ctor once
v.reserve(1000); // no ctor, good prior knowledge
if size is unknown then
v.reserve(as much);
v.shrink_to_fit();
vector<C>(c).swap(c);
Deque grows linearly with fix size instead of exponential size, no reserve() no capacity(), no reallocation so data reside at original places when new memory allocated. Because of the linked block of memory, locality is lower compared to vector that require more cache misses and page faults.

When to deque or vector?
both push front and back then deque. 
high performance then vector. 
For user defined class, vector performance drops closer to deque because object construction and destruction dominates the performance hit
Vector contiguous memory allocation difficult because of memory size limited, data too much and memory fragmented.
If data size completely unpredictable then use deque.
Vector push_back may cause memory reallocation and hence all pointers/references/iterators (pri) are all invalidated while deque push_back and push_front will not invalidate pri but note that deque insert at middle will invalidate pri.
Vector can be considered as raw array by using &v[0] except vector<bool> because vector of bool is optimized to store a bool in a bit instead of a byte and so the address of first element is not a pointer to bool but pointer to char. 

Object slicing
vector<P> v{C()};
v[0].m(); // call P.m() not C.m()
Object of C is parameter and copy constructed as P and store in vector v, also called object slicing.
P p=C(); // also object slicing

05 C++ My Notes (TBC)

05 C++ My Notes

When to use dynamic_cast?
Use dynamic_cast for polymorphic downcasting that would check type correctness at runtime with performance overhead, and return nullptr of type of castee is not compatible for the target type for pointer castee, or an bad_cast exception will be thrown for reference castee.

When to use static_cast?
Use it whenever possible to perform static checking by compiler to make sure type is compatible. Use it for upcast. Valid but dangerous to perform static downcast because may generate undefined behavior.

When to use reinterpret_cast?
It is the same as C style cast and should seldom be used.

When to use const_cast?
Scott Meyers said a good use of const_cast is to avoid code duplication by implementing the non-const member function in terms of const member function by first static casting the object itself as a const object to call the const member function, and then const cast away the const return type to non const type, i.e. T& get() {return const_cast<T&>(static_cast<const C&>(*this).get());


03 C++: C++ Modern Notes

03 C++: C++ Modern Notes

Initializer list for vector and constructor
C(const initializer_list<int>& v) {}
C v ={1,2,3}
C v{1,2,3}

Extend aggregate initialization to uniform initialization
C++03
Struct S { int a; int b; }; S s = {1,2}
C++11
Class C { C(int a, int b) {} }; C c = {1,2}

Uniform initialization order:
  1. Initializer_list constructor
  2. Regular constructor for arguments
  3. Aggregate initializer for data members
Class C { public:
C(const initializer_list<int>& first);
C(int second);
int third;
}
C c{1};

Auto type
auto x = v.begin(), 1, 2.1, y

foreach
for (int i: v), for (int& i: v)

nullptr replaces NULL
so f(nullptr) must call void f(char*) not void f(int), hence no ambiguity

enum class
enum class side {buy, sell};
enum class answer {yes, no};
side s = side::buy
answer a = answer::yes
s==a; // gives compilation error
Stronger type

static_assert
03: assert(p!=NULL); //runtime assert
11: static_assert(sizeof(int)==4);

delegating constructor
03: class C { C(){init();} C(int){init();} };
11: class C { C(){} C(int) : C() {} };

in class data member initialization
11: class C { int x=1; };

override in declaration
compilation in all three subclass functions
class P {
  virtual void A(int);
  virtual void B() const;
  void C();
};
class C : public P {
    virtual void A(double) override;
    virtual void B() override;
    virtual void C() override;
};

final class and final virtual function
class C final {}; cannot be derived
class C { void f() final {} }; cannot be override

default constructor
class C { C(int); C()=default; } ;

delete function
class C { C(int); C(double)=delete; C& operator=(const C&)=delete; };

constexpr for compile time
constexpr int MBtoKB(int MB) {return MB*1024;} int kb = MBtoKB(8);

unicode string literal
03: char* s="a";
11:
char* s=u8"a"; // utf8
chat16_t s=u"a";
chat32_t s=U"a";
char* s=R"2\\2"; // 2 backslashes

lambda function and variable capture
[](int x){return x*x;}(2); //4
auto f = [](int x){return x*x;};
f(2); //4
const int y=1;
[&](){return y+1;}; //2

r-value reference
void f(int&) {} void f(int&&) {}
int i=1; f(i); //1st f(1); //2nd

When Standard library return reference?
v[0]; get<0>(t); vector subscript, get tuple

3. Move Semantics

move constructor
copy constructor takes const l-value reference to make expensive deep copy
move constructor takes non-const r-value reference to cheaply steal its members
class C { C(const int&); C(int&&); };
void f(C c) {}
C c; f(c); calls l-value copy constructor
f(C()); calls r-value move constructor
Overload constructor from copy constructor to move constructor
Overload assignment operator from copy assignment operator to move assignment operator

move constructed
string f() {string s; s = "a"; return s; }
string s = f(); // RVO, string move constructed because of returning rvalue, otherwise copy constructed
vector<int> g() {vector<int>v{1}; return v;}
vector<int> v = g(); // RVO, vector move constructor, otherwise copy constructed

4. Perfect Forwarding
template <T> void r(T&& t) {f(std::forward<T>(t);}
T may not be r-value depends on the reference collapse rule that T& &, T&& & and T& && collapses to T& and T&& && collapses to T&&.
T&& is called universal reference that can take r-value, l-value, const and nonconst.
std::forward<T> cast values to T&&
template<T>
void relay(T&& t){foo(std::forward<T>(t));}
relay perfectly forwards lval and rval in one function only not two
std::move<T>(t); t casts to rvalue ref
std::forward<T>(t); t casts to T&& uni ref

5. User defined literals operator""
int, floating, char, string, 1, 2.1, 'a', "ab"
suffix 45, 45u unsigned int, 45l long
constexpr long double operator"" s(long double x) { return 1000*x;}

6. Compiler generated constructor
class C {};
class C { C(); ~C(); C(const C&); C& operator=(const C&); C(C&&); C& operator=(const C&); };
if move exists, copy wont be autogen
if copy exist, move wont be autogen
if destructor exists, only copy but no move, unless C(C&&)=default;

Broken copy constructor
class C {int* p; C(int x): p(new int(x)){} ~C(){delete p;} }; vector<C> v; v.push_back(); v.front().p;
// crash, push_back calls broken copy constructor

Vector requires object to be copyable or removable


7. shared_ptr
internal atomic increment ref count
shared_ptr<C> c = make_shared<C>("m");

9. Why weak_ptr?
shared_ptr leaks when cyclic reference because of mutual ownership
weak_ptr accesses the object without ownership that when and how object is delete is not related to weak_ptr

12. regex
#include <regex>
regex e("exact");
bool b = regex_match(s, e);
regex i("ignore", regex_constant::icase);
Repeat
. any character except newline
? 0 or 1 preceding character, +?-?, exist or not, abc? means ab following by an optional c, {0,1}
*means 0 or more preceding character, or any repeating of previous, abc* means ab followed by any number of c Z0+
+ means 1 or more preceding character, i.e. N, natural number
{3} exactly 3 times
{3,} 3 times or more
{3,5} 3 times to 5 times
Character
[cd] is a character of any one inside
[cd]* means c d cc dd cd ccc ddd cdcd
[^cd] means not c and not d, charet means negate all
Or
"ab|cd" means ab or cd
Escape
\{ means true {
Group the submatch
"(ab)" ab is a group that gives a submatch
"([ab])c*\\1" \1 means submatch 1, slash 1 escape slash 2, so aca bcb matches but acb not. Not submatch is the matched characters that may not be always the same as the group
Predefined set
[[:w:]] a word char : alnum + underscore
Draw a set diagram to match the classes in cplusplus.com
regex_match(s, e); match perfectly, 100%
regex_search(s, e); search partially, similar to google search
"^abc" search begin only (note ^ has overloaded meaning!!!)
"abc$" search end only

13. Regular Expression Grammar
ECMAScript(default), basic, extended, awk, grep, egrep
regex e("^abc.+", regex_constants::grep);
Then "+" is a pure plus not special in grep

smatch for getting matches
smatch is typedef match_results<string>
smatch m;
s="#a@b.c!"
regex e("([[:w:]]+)@([[:w:]]+)\.c");
bool b=regex_search(s,m,e);
m is vector-like, m.size() is 3
m[0] is whole string, m[1].str() is a, m[2].str() is b, m.prefix().str() is #, m.suffix().str() is !

14. Regex iterator skipped

15 + 16. Chrono skipped
system_clock, steady_clock, high_resolution_clock
std::ratio<1,10> r; r.num; r.den;

17 + 18. Random Number skipped

19. Tuple
pair<int, string> p = make_pair(1,"b");
p.first; p.second;
tuple<int, string, char> t(1,"b",'c');
make_tuple(1,"b",'c');
get<0>(t); get<1>(t); get<2>(t);
get<1>(t) = "new";
get<3>(t); compile error out range
bool b = t2>t1; // lexicalgraphical
t2=t1; member by member copy

tuple of reference
string a="aa"; string b="bb";
tuple<string&, string&> t(a,b);
get<0>(t)="aaa"; // a become aaa
t=make_tuple(ref(a), ref(b));
string x, y;
make_tuple(ref(x), ref(y)) = t;
tie(x, y)=t;
tie(x, std::ignore)=t;
auto t = std::tuple_cat(t1, t2);
tuple_size(decltype(t))::value; //4
tuple<0, decltype(t)>::type d; // d is a string

Tuple vs struct
struct { string name; int age; } a;
tuple<string, int> b;
a.name; a.age; // more readable
get<0>(b); get<1>(b);

20. When to use tuple?
  1. One time multiple data transfer
tuple<string, int> getNameAge() {make_tuple("a", 1);}
string x; int y; tie(x, y) = getNameAge();
  1. compare a group of data
tuple<int, int, int> t1, t2; t1<t2;
  1. Multi-index map
map<tuple<int, char, float>, string> m;
m[make_tuple(1, 'b', "c")] ="d";
  1. rotate data
int a, b, c;
tie(b, c, a) = make_tuple(a, b, c);

02 C++: C++ Advance Notes (TBC)

02 C++: C++ Advance Notes (TBC)

1. Const
const int i=0;
const int * const p = &i; // read from right
const_cast<int&>(i)=1; // ok, 1
int j=0;
const_cast<const int&>(j)=1; // error assign read only location

Why const?
Self documented intention. Avoid inadvertent write. Compiler optimize variable when it is defined with const by storing to program executable at compiler time. 

2. Const in function
class C { void f(int); void f(const int); };
cannot compiler overload f by const param
class C { const string & getName(); }; is good to return by const string ref.
const member function overloading
class C { void f() {}void f() const {} };
const reference argument overloading
class C { void f(string); void f(const string&); };

3. logic const with mutable vs bitwise const by compiler
class C { volatile int counter; } ;
const_cast<C*>(this)->count++; // also ok

4. Compiler generated functions
copy constructor, copy assignment operator, default constructor, destructor
All public, inline, generated only if have caller
class C{};
class C {
C(const C&){} // member initialization
C& operator=(const C&){} // member copy, not generated if const member or reference member
C(); // base default, member default
~C(); // Member destroy, base destroy
class C { C()=default; }; // force generate

5. Disallow function
class C { public: C(C&)=delete; }; // no call
Use =delete or privatize the function
private destructor does not compile when used as stack object, forcing store at heap

6. Virtual destructor
factory pattern is a centralized place to produce objects.
Use virtual destructor.
Use shared_ptr without virtual destructor also works, but unique_ptr will not work.
All C++ standard library has no virtual destructor. 

7. Exception in destructor
Crash if exception thrown in destructor
Solution is to swallow all exceptions in destructor, or move exception-safe code away from desctructor





What is rvalue?
R value cannot be addressed
2 = i; so 2 is r value
&(i+1); so (i+1) is r value
(i+1)=2; so (i+1) is r value
&C(); so C() is r value
&sum(1,2); so sum(1,2) is r value


What is reference?
A variable reference a lvalue
So int& i=5; compiles error
const int& i=5; is 2 step. Step 1: temp l value assigned with 5 2. Reference a temp l-value
int f(int& i) {}; f(1); //compile error
int i=1; int j=i; l-value i is implicitly transformed to r-value before assignment
r-value can be used to create l-value:
int v[3]; *(v+2)=0; // r-val become l-val

Misconcept: Operator can return l-value
int g; int& f(){return g;};
f()=1;
(a+b)=1;
v[0]=1;

Misconcept: l-value always modifiable
In C yes. In C++ no, because of const int i;

Misconcept: r-value not modifiable
No. c().f(); the r value c() state is modified.

Expression is either l-value or r-value where l-value has identifiable memory address.

2023 Promox on Morefine N6000 16GB 512GB

2023 Promox on Morefine N6000 16GB 512GB Software Etcher 100MB (not but can be rufus-4.3.exe 1.4MB) Proxmox VE 7.4 ISO Installer (1st ISO re...