Quick C++
Posted on July 1, 2014
Tags: c
1 CMakeList
First install mvs-code CMake toolkit
1.1 Quick Start
>CMake: Quick Start
> Select kitsGCC 11.2.1 x86..
> Input Name of project > SelectExecutable
- Optional Changing compiler:
>CMake: Configure
> SelectGCC 11.2.1 x86..
- Optional Changing compiler:
>CMake: Select Variant
> SelectRelease
>Cmake: Make Build
Go to /build dir and run the executable.
2 Starter
#include <bits/stdc++.h>
template <typename T>
void print(const T &t) {
std::cout << t << std::endl;
}
template <typename O,typename T>
void print(const O label, const T &t) {
std::cout << label << ": " << t << std::endl;
}
template <typename T>
void print(const std::vector<T>& t) {
for(auto i: t){
std::cout << i << " ";
}
std::cout <<std::endl;
}
template <typename O,typename T>
void print(const O label,const std::vector<T>& t) {
std:: cout << label << ": ";
for(auto i: t){
std::cout << i << " ";
}
std::cout <<std::endl;
}
template <typename T, typename R, typename L>
void fmap(const T& t, R& result, L lambda ){
(t.cbegin(),t.cend(),result.begin(),lambda);
transform}
template <typename T, typename B, typename L>
auto foldl(const T& t, const B base, L lambda ){
return accumulate(t.cbegin(),t.cend(),base,lambda);
}
template <typename T, typename B, typename L>
auto foldr(const T& t, const B base, L lambda ){
return accumulate(t.crbegin(),t.crend(),base,lambda);
}
//functional format instead of int maxd(){}, we do auto maxd()-> int{}
auto maxd(int a, int b) -> int{
return 5;
}
using namespace std;
int main(){
//--------------------------------------------------------
//lambda
auto lambdaX = [](int x){return x + 9;};
("lambda applied to 8",lambdaX(8));
print("lambda type", typeid(lambdaX).name()); //type of lambda
print
//lambda expression = (lambda a: a + 9)(8)
int pp = [](int x){return x + 9;}(8);
//--------------------------------------------------------
<int> intlst = {1,2,3,4};
vector<int> results(intlst.size());
vector//cbegin and begin are iterators
//cbegin is constant, begin is not, begin iterator can change the value pointing to
//fmap is a template for transform
(intlst.cbegin(),intlst.cend(),results.begin(),[](int x){return x + 3;});
transform(intlst,results,[](int x){return x + 3;});
fmap("transform",results);
print//--------------------------------------------------------
//accumulate is foldl, the state transition fold
auto Sum = accumulate(intlst.cbegin(),intlst.cend(),0,[](int x, int y){return x + y;});
auto Sum2 = foldl(intlst,0,[](int x, int y){return x + y;});
("accumulate",Sum2);
print("foldl",Sum);
print
auto Largest = accumulate(intlst.cbegin(),intlst.cend(),0,[](int x, int y){ return x > y ? x : y;});
("largest",Largest);
print
//--------------------------------------------------------
//foldl works from left inner parenthesis outwards
= "MSFT";
string InStr = "|";
string k auto paren = foldl(InStr,k,
[](auto IH, auto nextStep){
= "(" + IH + nextStep + ")";
string v return v;
}
);
("foldl",paren);
print//outputs ((((|M)S)F)T) for foldl
//(((|M)S)F) is IH,
// T is nextStep
//--------------------------------------------------------
auto parenR = foldr(InStr,k,
[](auto IH, auto x){
= "(" + IH + x + ")";
string v return v;
}
);
("foldr",parenR);
print//outputs ((((|T)F)S)M) for foldr
// can also be rewritten as (M(S(F(|T))))
// (S(F(|T))) is IH
// M is x
// in haskell list x:xs, x operates on IH(xs).
auto Reverse = foldr(InStr,k,
//input MSFT
[](auto IH, auto x){
= IH + x ;
string v //IH represents reverse(SFT)
//x represents "M"
return v;
}
);
("foldr reverse",Reverse);
printreturn 0;
}
3 Smart Pointers
In general, a function should take:
- A copy of a shared_ptr, if the function takes part in the ownership of the managed object
- A reference to a shared_ptr if the function plans to modify the shared_ptr itself by calling reset or swap
- A reference to a const shared_ptr, if the function might take part in the ownership by copying the reference to another shared_ptr on at least one of its paths
- A raw pointer/reference to the object, if the function is only interested in the current value of the managed object
4 Rvalue Lvalue
5 Virtual functions
- problem: classes that extend base classes will call base class method on compile time.
- What if constructed using
Animal x = new Cat()
instead of canonicalCat x = new Cat()
x.voice()
x will only call it’s base classAnimal
methods. BAD
- What if constructed using
- solution: virtual method allow dynamic binding so the proper object method is found and called on run time
- make
x.voice()
a virtual function- x will now call it’s proper Object method
Cat
which is discovered on run time.
- x will now call it’s proper Object method
- make
class Base
{
public:
void Method1 () { std::cout << "Base::Method1" << std::endl; }
virtual void Method2 () { std::cout << "Base::Method2" << std::endl; }
};
class Derived : public Base
{
public:
void Method1 () { std::cout << "Derived::Method1" << std::endl; }
void Method2 () { std::cout << "Derived::Method2" << std::endl; }
};
* basePtr = new Derived ();
Base// Note - constructed as Derived, but pointer stored as Base*
->Method1 (); // Prints "Base::Method1"
basePtr->Method2 (); // Prints "Derived::Method2" basePtr
6 Etc
int pp()
: Even though we return g, all we really get is a copy of VALUE of g.
int pp(){
int g = 5;
(&g); //0x7ffeaa2e6d64
logreturn g;
}
int main(){
int v;
(&v); //0x7ffeaa2e6d8c
log= pp();
v(&v); //0x7ffeaa2e6d8c
log}
int* pp()
: we get a copy of the ADDR of g. YET the VALUE of g is destroyed.- LESSON: the only thing that persists from
int* pp(){..}
is the return typeint*
- Just focus on return variable of the function
- Even if you return a pointer, like
int*
, if it points to a destroyed local var from the function stack, it’s basically worthless.
int* pp(){
int *p;
int g = 5;
= &g;
p ("addr of g",p); // 0x7ffcebeead24
logassert(p == &g);
("value of g", g); // 5
logreturn p;
}
int main(){
int* v;
= pp();
v("addr of g:",v); //0x7ffcebeead24
log("value of g", *v); // 0
log}
//notice has the value of g is destroyed when assigning it to v.
- manual allocation allows stuff to exist even after function stack gets destroyed.
- LESSON: function stack gets destroyed but HEAP manual allocation like
new
malloc
persists
int* pp(){
int *p = new int(); //this lives outside the function on the HEAP until manually deleted
*p = 5;
("addr of g",p); // 0x2079eb0
log("value of g", *p); // 5
logreturn p;
}
int main(){
int* v;
= pp();
v("addr of g:",v); //0x2079eb0
log("value of g", *v); // 5
logdelete v; //this is where we delete the allocated *p
}
- pointers allow us to dynamically allocate an array based on user input.
- Without pointers we are forced to hard-code size of array.
int main(){
int* v; //with a pointer we can dynamically allocate an array
int cnt ;
>> cnt;
cin = new int[cnt]; //like this
v for(int i = 0; i < cnt; i++){
[i] = i;
v}
for(int i = 0; i < cnt; i++){
(i,v[i]);
log}
delete v;
}
6.1 arrays
- 2d arrays cannot be built like this
int v[2][2] = new int[2][2]
- 2d arrays cannot be passed as arguments like
void func(int stuff[][])
because the size is not specified
6.2 array as pointers
int main(){
// ptr ptr --*--> ptr --*--> val
//init START
int **v;
int row;
>> row;
cin = new int*[row];
v
int col;
>> col;
cin for(int i = 0; i < col; i++){
[i] = new int[col];
v}
// init END
for(int i = 0; i < row; i++){
for(int j = 0; j< col; j++){
[i][j] = i*j;
v}
}
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
(v[i][j]);
log}
}
delete v;
}
Deref a = a[0]
- A pointer is more powerful than an array
- Anytime we have an array we can replace it with a pointer