C++ 101

goal

  • Features and existence
  • read documentation
  • Design philosophy of modern cpp

Fundamentals

highly evolving, absorb other languages features, multi-paradigm, effcient in time and space

  • history of cpp

Assembly -> c -> c with classes

  • Design philosophy of c++

    • Paradigm, multiple paradigm

    • Performance

    • Abstraction: compartmentalize messy constructs

types and structs

  • types
  • structs
  • type deduction with auto
  • structured binding

initialization and references

streams

overview

Interact with outside like sockets in internet or programs as pipelines

Stream is like a character buffer: make conversion between external source, variables representations in program.

4 standard iostreams: cin, cout, cerr, clog

cin reads whitespace not consuming it until next call of cin.

1
getline();

stringstream

  • when to use stringstream? compared to str
    • processing strings
    • Formatting input/output
    • parsing different types

buffered state: JG(short for just google)

  • type conversion

Overwrites, use ::ate

1
2
3
4
5
osstringstream oss("...");
cout << oss.str() << endl;

istringstream iss("..."); //automatic conversion
iss >> ..;

pointer points to the end of stringstream, so it can be written from where it ends last.

position of pointer can be changed using …(Just Google). stringbuf is for more low-level control(pointers).

?

initializa a os stream, writing to it would be overwrites unless specified. keep writing, which would continue from the end of last stream.

  • Delimiter

    • Read string: whitespace separated token, token preference
    • Stream stops: whitespace or invalid type matched
  • stringstream formatted i/o

    • Why operator works?

      Operators return a reference to the stream itself. It’s like that streams eat whatever left and become much longer

  • Practice: write stringtointeger;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int stringToInteger(const String& s) {
istringstream iss(s);
int temp;
iss >> temp; //losing part:parsing process, else temp not initilized
if (iss.fail()) throw std::domain_error("error"); //no value int at beginning

char remain;
iss >> remain;
if (!iss.fail()) throw std::domain_error("error"); //more than a single valid int

printStateBits(iss);

return temp;
}

Fix: Errornous input

state bits

  • Check for errors? what the error message means?

    Detect error messages: by reading partial stream

  • state

    • good bit

      • rarely used
    • fail bit !

    • EOF bit !

      • on only read passing the end
    • bad bit

  • State bits act as boolean value of stream

    expression be like (iss >> result)

Input/output streams

  • Buffering

    Buffering stuff won’t print to console instantly?

  • Rushing

    • endl = ‘\n’ + flush(print to console) : much slow, don’t use too much

    • ‘\n’(without flushing)

  • Input stream problems

    read token by token, trash would stop reading of cin, redundancy.

    • How to solve it?
  • getline return value?

1
2
3
if (!getline(cin, line)) throw domain_error(...);

iss.ignore(); //skip one place

manipulators

keywords will change the behavior of the stream when inserted, serving as functions

types

1
2
3
4
5
//unsigned int, signed int: cause type unmatched error.
string str = "hello world";
for (int i = 0; i < str.size(); ++i) //error
for (size_t i = 1; i < str.size() - 1; ++i) //if str is empty, it will run into trouble for -1 size. And you will always miss the last element of str.
for (size_t i = 0; i < str.size(); ++i) //correction
  • type aliases

    • long
  • Auto

    • Cstring, cppstring: array(unknown size) vs. string
    • drop c stuff (reference, const)
    • when to use
      • only necessary : explicit, lambda, …
      • Don’t return auto type generally
      • can’t use in parameters of functions
  • Pair/tuple functions

    • structured binding(cpp17), learn from python

      • Drawbacks: implict binding, may use struct instead

        ex: Pairt(min, max)

  • Struct

    • Light way of class
    • Public (class may not)
    • Semicolon at the end!
1
2
3
4
5
6
struct discount{

};

//pair
//struct
  • Parameters(in) and return values(out) guidelines for modern c++ code

    ??

    when to return reference

  • uniform initialization(cpp11)

    Multiple way of initialization depending on types

    • automatically deduced the type, like struct

    • initializer list

standard template library

overview

Open source

efficiency : think problems in depth

Sequence containers

Store stuff, container

std::vector bounds check by default

  • segmentation fault won’t happen

  • Drawbacks

    • fail silently, don’t where goes wrong
    • Write correctly, slow down the program
  • grow rapidly in one direction, so push_back slow case can be substituted of deque

associative containers

  • container adaptors

    Stack: first in first out ->Push back, pop back

    Queue: first in last out ->Push back, pop front

    • Build at the base of deque, why not deque?
      • Design philosophy: express directly and abstraction without losing efficiency, allow full control for programmers
  • associative containers: key, value pairs

    Map, set:

    • ordered or not
      • Ordered: < less than, sorted keys
      • Hash functions
  • iterators

    • usage: begin, end
      • create, dereference, advance, compare
    • Iterate through any container, which is powerful
      • apply the same logic action to containers regardless of which data structures it is.
    1
    2
    3
    set<int>::iterator iter = mySet.begin(); //define type autoamtically by qt
    int val = *iter;
    iter++; //or ++iter;
    • multimaps

      Same key different values

  • map iterators

    Using pairs: std::pair

    • Access through *
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //ways to create pairs(3...)

    //map iterators
    map<int, int> m;
    map<int, int>::iterator i = m.begin();
    map<int, int>::iterator end = m.end();
    while (i != end) {
    cout << (*i).first << (*i).second << endl; //not *i.first
    ++i;
    }

advanced containers

  • further iterator usages

    • Iterator is just memory address

    • vector end points to in c++

      The C++ function std::vector::end() returns an iterator which points to past-the-end element in the vector container. The past-the-end element is the theoretical element that would follow the last element in the vector.

    1
    2
    3
    4
    5
    6
    7
    set<int> mySet{1,3,57,137};
    set<int>::iterator iter = mySet.lower_bound(2);// strictly greater than

    for(; iter != end; ++iter) {
    cout << *iter << endl;
    }

    • Find, count

    • ranges based for loop

      short for iterator

  • Quick note on structs

    declare, initialize, operate(dot notation to enter field)

  • iterator types

    Incremented iterators, jump far iterators

    1
    2
    std::list<int> myLIst(10);
    auto some_iter = myList.begin() + 3;//error, list not supported this kind of iterator

    Input/output <- forward <- bidirectional <- random access

    • similarity: above
    • diff
      • Input: read only, move in single direction
      • Output: write only
      • Forward: read and write, multiple passes,
      • Bidir: go forwards or backwards
      • Random access item: ++, – arbitrary amounts(most powerful)

templates

  • programming paradigm

    • oop: java, python
    • Procedural programming: c
    • generic programming
  • template functions

    • Overload programs, generic type in java, but in c++?

      it turns out to be the same.

      Template augmentation help(JG)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      template <typename T>  //declare T is a type
      pair<T, T> my_minmax(T a, T b){
      return;
      }

      auto [min, max] = my_minmax<double>(2.3, 4.3); //explicitly instantiating, specify the type
      auto [min1, max1] = my_minmax("Ad", "Av"); // implicitly. type should be c string, which would not convert to cpp string as explicitly isntantiating.

      //in case there is a large collection
      //pass in the pointer of object,
      //const T& a

  • varadic templates(since c++11)

  • concept lifting

    • generic programming

    • concept lifting

      • relax constraints? Is certain type necessary?

      • Iterate through all elements

Function&algorithms

Cpp compile and run

1
g++ -std=c++17 program -o program_executable_filename
  • Implicit interfaces

    given a piece of program, determine what it suggest?

  • concepts c++20: explicit interfaces

    1
    2
    3
    template <typename It, typename Type>
    requires Input_iterator<It> && Iterator_of<It> && Equality_comparable<value_type<It>, Type>
    int countOccurences(It begin, It end, Type val);
  • lambdas

    Q:How many times does the element satisfy equal[val] in [a range of elements]?

    • [Predicate(JG)] : return boolean
    1
    2
    3
    4
    5
    6
    if (predicate(*iter)) ++ count; //predicate typeL UnaryPred


    //predicate in template
    template <typename DataType>
    inline bool isEven(DataType val) {return;}
    • problems encountered
      • annoying to write separate functions for solving similar tasks
      • scope issue: a variable limit in the calling function
    • Solve: lamda functions (since c++11
      • Semicolon at the end!(compared to function)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //anatomy of a lambda function
    auto func = [capture-clause](parameters) -> return-type { //auto is required
    //body
    };

    //ex
    auto isLessThanLimit = [limit](auto val) -> bool { //bool can be ommitted since it is predicate
    return val < limit;
    };
    • [Capture-clause]
      • by value: [=]
      • by reference: large sets [&]
      • (never)Lazy: capture all the available [=, &exception]
  • Algorithms library

    • Sort, copy, partition,

    • Stream iterator

      1
      std::copy(courses.begin(), courses.end(), std::ostream_iterator<Course>(std::cout, "\n"));
    • Problems run into:

      • find

        Which data structure is faster?

      • Remove

        can’t remove actually : remove is not in the vector algorithms

        1
        2
        3
        4
        5
        //fix: erase-remove idiom
        v.erase(
        std::remove_if(v.begin(), v.end(), predicate), //return iterator to beginning of trash, s.t.it can be removed later
        v.end()
        );
      • copy:

        limited container size: expand the size

        1
        back_inserter(csCourses); //iterate the container
  • adaptors

  • ranges

Modern stl

  • Conclusion

    • Boost is one layer above.

    • abstraction

      Basic types -> containers -> iterators -> algorithms

      🧐it’s fascinating of all those abstraction levels

Ex: matching

Word frequency count -> similarity - > dot product

Writing a program from scratch

1
2
3
4
5
6
7
#include <iostream>  

//using namespace
using namespace std; //single class
//so instead
using std::cout; using std:endl //specify which coutstream of library is using; multiple classes work together

Decompose, from top down

classes

oop basic syntax

Extensions decided by compilers

  • constructor and destructor

  • Const keyword

  • operator overloading

oop design

const

Decide scope used

  • const correctness

    • why use const? safety always matters.
    • why not global variable? hard to track

    It’s like immutable and hashable value in python. There is price to make to use lists.

    • const allows us to reason about whether a variable will be changed
  • const cast : not a good way

    Why ?

  • Const and classes

    Object can be divided into two state: const, non-const

    Const interface, non-const interface

    Const object can only be passed into const interface while non const object is fine for both interface

    • Const pointer:

      pointer allow to move or not

      (pointer read from right to left)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      //constant pointer to a non-constant int
      int * const p;

      //non-constant poiter to a constant int
      const int* p;
      int const* p;

      //constant pointer to a constant int
      const int* const p;
      int const* const p;
  • const iterators

    1
    2
    3
    const vector<int>::iterator itr //like int* const itr

    const int* const myClassMethod(const int* const & param) const; //means what,const pointer point to const member function which takes const pointer to a const int.

    |The last const means this is a const member function(can’t modify variables of the this instance)

    • can use autos
  • review

    • Generally, we use const when things does not get modified.
    • Pass by const reference is better than pass by value
      • exception: Boolean
    • member functions have both const and non-const iterators

    more specificly,

    • const on objects
    • const on functions

operators

when to overload? Principles?design choice?

  • operator overloading

    (40+4)

    how to apply operators to user-defined classes?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //function signature
    //sth vector<string>::operator+=(type element)
    [return] StringVector::operator+=(const std::string& element)


    //operator overloading
    push_back(element);
    for (int val: other) push_back(val); return [something?];

    //why reference?
    //return by value?by const?by reference?


rules for member vs. non-member

:Member function, non - member function(contains itself or not)

  • which type should be passed in?

    Operator needs reference? values?

1
2
3
4
5
ostream& operator<<(std::ostream& os, const Fraction& F){

}
//cout << fraction1 << fraction2
cout.operator<<(franction1).operator<<(fraction2)
  • Think about const vs. non-const for member functions.
1
2
... (){};
const ... () const{};
  • Friend
1
2
3
4
5
6
7
class Fraction{
public:

private:

friend operator<<(...) //friend(outside, non-member) can access private member varible of class
}
  • Rules for members vs non-members

    Some are better for member(allow easy access to lfs private members), some are not, depending on treating both operands equally.

    • member

    • Non-member

    • unary

    • Binary

  • canonical forms

  • POLA, principle of least astonishment

    if a necessary feature has a high astonishment factor, it may be necessary to redesign the feature

Special member functions

automatically generated by the compiler:

default construct,

copy constructor, (copy from l)

copy assignment, (overwrite from l)

destructor

  • construction vs assignment

    deepcopy

    special case: avoid self-assignment

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //asign
    StringVector& StringVector::operator=(const StringVector& other) {
    //
    //
    //
    //
    delete[] elems;

    elems = new std::
    return *this;
    }
  • details and delete

    prevent copy

  • rule of three/zero

    Default one not working: ownership issues

    • rule of three: if you explicitly define(or delete) one special member function, you should define(or delete) all three
    • rule of zero: reduce redundant work if orginals working
  • copy elision

    Compiler helps

move semantics

Moving is more efficient than copying

  • Lvalues vs. rvalues

    lvalues, long term(name and identity), has address

    rvalues, temporary, no address

    • key to move semantics: l copy, r copy and move
    1
    2
    auto& ptre = ptr;
    auto&& v4 = v1 + v2;
  • Move constructor and assignment(special member functions)

    • move constructor(create from r)
    • Move assignment(overwrite from r)
    1
    2
    //r reference is lvalue
    //sol: unconditionally cast, std::move()
  • swap

1
2
3
4
5
6
7
template <typename T>
void swap(T& a, T& b){
T temp = a; //std::move()
a = b;
b = temp;
}

  • perfect forwarding

    emplace_back(vector)

namespaces

  • scope resolution

    1
    2
    std::    ;
    StringVector:: ;

inheritance

c+±specific details

explicit interface, implicit interface

abstract classes: any class contains at least one virtual function

  • Access specified keyword :

    • public,
    • private,
    • protected
  • inherited members

    • struct
  • Pure function vs non-pure function

    Pure function must be inherited while non-pure function can be chosen to be inherited or override, which reflects on the syntax below.

1
2
3
4
5
6
7
8
9
10
//pure virtual function
virtual void make() = 0; //Virtual in interface: enforce function defined by subclasses
//non-pure virtual function
virtual void make2();
//regular
void bar() == {return 33;}

class Tea : protected Drink { //functions in drink become protected functions in tea

} //struct just defaults into public
  • call superclass constructor
    subclassname::subclassname(params)
    : superclassname(params) {
    statements;
    }

  • call superclass member
    superclassname::membername(param){
    statements;
    }

  • terminology

    • Base class
    • derived class
    • non-virtual destructors
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>
using std::cout; using std::endl;
class Drink{
public:
Drink() = default;
Drink(std::string flavor) : flavor(flavor){}

virtual void make() = 0;
virtual ~Drink() = default;

private:
std::string flavor;
};

class Tea : public Drink {
public:
Tea() = default;
Tea(std::string flavor) : Drink(flavor) {}
~Tea() = default;

void make() {
cout<< "" << endl;
}


};

int main() {
Tea t("red");
t.Drink::make();

return 0;
}

  • templates vs. derived classes

    Statics vs. dynamic polymorphism: run time vs. compile time

    when to use each?

  • casting

    1
    2
    3
    int a = (int)b;
    int a = int(b);
    int a = static_cast<int>(b); //best practice, static int

Template classes

function template

class template

1
2
3
4
5
6
7
8
struct Node {

};
//template <typename T>
template <class T, class Container = std::vector<T>>
class PQ{

};

concept(c++20)

Implicit interface

concept: named set of constraints

1
2
3
4
template<class D, class B>
void f(T) requires DerivedFrom<D,B> {

}

modern cpp

raII

  • Different code paths, delete method may not sufficient to handle meomory leaks.

    can’t guarantee the ‘delete’ call is called if an exception is thrown -> RAII complaint

  • exception

    • Nothrow exception guarantee, strong ,basic, no(memory corruption, resource leaks)
  • raii: resource acquisition is initialization

    • Meaning

      • scope based memory management,

      • or constructor acquires, destructor realeases

        Wrap up in one object

    • avoid using new/delete explicitly

      Automatic memory management good?

PIMPL: pointer to implementation

  • smart pointers: implement pointer

    • std::unique_ptr: one pointer to one resource

      • can’t be copied

        Syntax: by deleting the copy constructor and copy assignment

    • std::shared_ptr: multiple pointer to same object

      • Deleted when none of them point to it
      • works only when the new pointers are made through copying
      • reference counting: abide some rules
    • std::weak_ptr: circular references of shared_ptr(JG)

    how to create these pointers?

    1
    2
    3
    4
    5
    std::unique_ptr<Node> n (new Node);
    std::shared_ptr<Node> n (new Node);
    //use built-in smart pointer creators
    std::unique_ptr<Node> n = std::make_unique<Node>();
    std::shared_ptr<Node> n = std::make_shared<Node>();

    when to use built-in creator rather than original?

    Rules:??sth about function,(timestamp 48:20)

multithreading

c

template mateprogramming

  • computations on types
  • Mata-functions and implementing identity
  • template deduction and implementing is_same
  • Wrap up