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 | osstringstream oss("..."); |
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 | int stringToInteger(const String& s) { |
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 | if (!getline(cin, line)) throw domain_error(...); |
manipulators¶
keywords will change the behavior of the stream when inserted, serving as functions
types¶
1 | //unsigned int, signed int: cause type unmatched error. |
-
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 | struct discount{ |
-
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
- Build at the base of deque, why not deque?
-
associative containers: key, value pairs
Map, set:
- ordered or not
- Ordered: < less than, sorted keys
- Hash functions
- ordered or not
-
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
3set<int>::iterator iter = mySet.begin(); //define type autoamtically by qt
int val = *iter;
iter++; //or ++iter;-
multimaps
Same key different values
- usage: begin, end
-
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
7set<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
2std::list<int> myLIst(10);
auto some_iter = myList.begin() + 3;//error, list not supported this kind of iteratorInput/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
12template <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
3template <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
6if (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 |
|
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
3const 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 | ostream& operator<<(std::ostream& os, const Fraction& F){ |
- Think about const vs. non-const for member functions.
1 | ... (){}; |
- Friend
1 | class Fraction{ |
-
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
2auto& 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 | template <typename T> |
-
perfect forwarding
emplace_back(vector)
namespaces¶
-
scope resolution
1
2std:: ;
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 | //pure virtual function |
-
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 |
|
-
templates vs. derived classes
Statics vs. dynamic polymorphism: run time vs. compile time
when to use each?
-
casting
1
2
3int a = (int)b;
int a = int(b);
int a = static_cast<int>(b); //best practice, static int
Template classes¶
function template
class template
1 | struct Node { |
concept(c++20)¶
Implicit interface
concept: named set of constraints
1 | template<class D, class 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
5std::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