Cpp101 Week 3
Cpp101 Week 3
Day 1
C++ 11 introduced lambda expressions to allow inline functions which can be used
for short snippets of code that are not going to be reused and therefore do not
require a name. These are very helpful when you have to define a function inside a
function itself and also need all the local variables of the current functio
itself but in case of multiple return statements, the return type needs to be
explicitly declare
There are several ways to access all the variable that lie in the function that
Lambda functions are apparently better optimised by the C++ compiler because
these are nothing just function objects. Learn more about it here
Also you can follow this guide to learn how lambda functions are used in
competitive programming USACO Guide
Some notes:
Earlier you cannot use templates while defining the lambda function but from
C++-20 it is possible [ discussion
You need to be very careful when you are using a lambda function as a
recursive function because compiler needs to know that there exists such
function in the enclosing domain so either you pass the lambda function in the
argument list itself or first declare the function and add it’s body later [ Read
more about it here
You can recap your prior knowledge of l-value and r-value studied in week 2 by
this video or this article
Move Semantics
Whenever you assign a constant value to some object the value is copied to
target object which is a costly operation. Many times there is no need to copy the
rvalue to an object’s data, we just need to move it’s value, this is where move
semantics comes in
Now go through this article if you want to have a more clear understanding of the
topic
std :: move( )
Whenever you want to convert the lvalue to an rvalue you can use a function in
the standard library ‘std::move(object)’
You can learn from cpp reference or from here and here
Since now we know about move semantics and the need of it, we will make a
move constructor for the complex-numbers class.
Similar to how we have a copy assignment we can have a move assignment too
Till now you know the rule of big-3 i.e. each class should have at-least these three
functions
A default constructo
A copy constructo
A destructor
But now since we know about move semantics we would extend it and now say
that in addition to these a class should have a move constructor and move
assignment operator too
Suppose you are calling a function anywhere in your program that requires a
object to be passed and function may change the value of the object and you
want the change to be reflected in the function where you called it.
There are two ways to solve this either use the object pointer or use lvalue
reference as shown below :
We have already seen how easy it is to iterate through the elements of the
iterator using for(auto i : v) But there is a problem in this technique whenever you
iterate over the elements of v like this, for each iteration you are creating a copy
of i, that is for each iteration i is just a copy of the element present at that
position. Now this would be very costly if v is suppose a vector of vectors, then
for each iteration we are creating a new copy of a vector. So again an efficient
way to do is using lvalue referencing as follows :-
us
push_back( ) vs emplace_back( )
push_back( ) and emplace_back does the same thing of pushing an object at the
end of a vector but there is a minor difference (which can have impact on the
to push an object(say obj1) in it. So when you call the push_back function, the
program calls the copy constructor of the class to which the obj1 belongs thus
creating a temporary object. This object is now copied to the end of the vector
just take a list of arguments of the object creating an object at the end of the
vector using the default constructor of the class thus saving time and space
v = { {1,2}, {3,4}}
Perfect Forwarding
Suppose you have a function whose input types(whether they are lvalue of rvalue
references) are not known yet( so you use template while defining the function
body) and inside the function body you call another function whose inputs are
same as the given inputs but since we don’t know the type of the inputs this may
cause us to overload the first function for all possible inputs which may grow
forward which forwards the argument to another function with the value
Algorithms Library
The algorithms library defines functions for a variety of purposes (e.g. searching,
sorting, counting, manipulating) that operate on ranges of elements. Note that a
range is defined as [first, last) where last refers to the element past the last
element to inspect or modify.
all_of, any_of, none_of: Find whether a predicate is true for all/any/none of the
entries in a range. More: all_of , none_of and any_o
find: Finds the iterator to the first occurrence of an element in the range, if
none is found, the function returns last. Mor
find_if, find_if_not: finds the iterator to the first element which returns true/
false on the predicate respectively, if there is no such element, then the
function returns last. Mor
search: Searches for the first occurrence of a particular sequence in the range,
and returns the iterator to the first element in the range, and last if no such
sequence exists. Mor
copy_if: Copy all elements in a given range that test true for a specified
condition. Mor
fill: Assigns the same new value to every element in a specified range.More
lower_bound: Finds the position of the first element in an ordered range that
has a value greater than or equivalent to a specified value, where the ordering
criterion may be specified by a binary predicate.Mor
max: Compares two objects and returns the larger of the two, where the
ordering criterion may be specified by a binary predicate, similarly, the
function min is defined.More, Mor
minmax: Compares two input parameters and returns them as a pair, in order
of least to greatest. Mor
next_permutation: Reorders the elements in a range so that the original
ordering is replaced by the lexicographically next greater permutation if it
exists, where the sense of next may be specified with a binary predicate,
similarly, the function prev_permutation is defined.More, Mor
partition: Classifies elements in a range into two disjoint sets, with those
elements satisfying a unary predicate preceding those that fail to satisfy
it.Mor
partial_sort: Arranges a specified number of the smaller elements in a range
into a non-descending order or according to an ordering criterion specified by
a binary predicate.Mor
remove: Eliminates a specified value from a given range without disturbing the
order of the remaining elements and returning the end of a new range free of
the specified value.Mor
If you want to learn more about this amazing library, then check these articles:
Article-
Article-
Article-3
Day 3
The I/O system of C++ contains a set of classes which define the file handling
methods.
Just like how we use the iostream library which provides cin and cout methods for
reading from standard input and writing to standard output respectively, there
exists another standard C++ library called fstream (which has memeber classes
ifstream, ofstream and fstream) , using which we can read and write from a file.
ios - It stands for input output stream and is the base class for all other classes
istream - It is derived from the ios class and stands for input stream. The
extraction operator (>>) is overloaded in this class to handle input streams from
files to the program execution.It also declares input functions such as get( ),
ostream - It is also derived from the ios class and stands for output stream. The
files from the program execution. It declares output functions such as put( ) and
write( )
fstreambase - This class provides operations common to the file streams and
ifstream - This class represents the input file stream and is used to read
ofstream - This class represents the output file stream and is used to create
fstream - This class represents the file stream, and can be used to both read
streambuf - This class contains a pointer which points to the buffer which is
filebuf - Its purpose is to set the file buffers to read and write and it is also used
Like the cstdio header inherited from C's stdio.h, iostream provides basic input and
output services for C++ programs. iostream uses the objects cin, cout, cerr, and
clog for sending data to and from the standard streams input, output, error
(unbuffered), and log (buffered) respectively. As part of the C++ standard library,
these objects are a part of the std namespace.
iomanip on the other hand stands for input output manipulation and is used to set
the properties of an iostream object. It includes important functions such as
setprecision() , setbase() and put_time()
The cin object in C++ is an object of class iostream. It is used to accept the input
from the standard input device i.e. keyboard. It is associated with the standard C
input stream stdin.
The extraction operator(>>) is used along with the object cin for reading inputs.
The extraction operator extracts the data from the object cin which is entered
using the keyboard.
Since it is an object it also contains many member function like cin.getline() and
cin.read() Learn more about cin from this article
header file. It is used to display the output to the standard output device i.e.
The data needed to be displayed on the screen is inserted in the standard output
Similar to cin it is also an object and contains member functions such as cout.put( )
and cout.write( ) etc. You can learn more about them here
The cerr object in C++ is used to print error messages. It is defined in the iostream
header file.
The clog object in C++ is an object of class iostream. It is associated with the
clog and cerr, both are associated with stderr, but it differs from cerr in the sense
that the streams in clog are buffered and not automatically tied with cout. We will
Stream buffers represent input or output devices and provide a low level interface
for unformatted I/O to that device. Streams, on the other hand, provide a higher
level wrapper around the buffer by way of basic unformatted I/O functions and
especially via formatted I/O functions (i.e., operator<< and operator>> overloads).
streambuf object helps to access these buffers.You can learn more about them in
The buffer flush is used to transfer of computer data from one temporary storage
area to computers permanent memory. If we change anything in some file, the
changes we see on the screen are stored temporarily in a buffer.
Generally competitive programmers include these two lines at the starting of their
main function to increase the speed of input and output. Here we explain their
significanc
ios_base::sync_with_stdio(false);
It toggles on or off the synchronisation of all the C++ standard streams with
their corresponding standard C streams if it is called before the program
performs its first input or output operation. Adding it changes the property
sync_with_stdio to false (which is true by default). It is a static member of the
function of std::ios_base.
cin.tie(NULL);
tie() is a method that simply guarantees the flushing of std::cout before std::cin
accepts an input. This is useful for interactive console programs which require
the console to be updated constantly but also slows down the program for
large I/O. The NULL part just returns a NULL pointer.
endl vs ‘\n’
Endl and ‘\n’ appears to do the same thing of adding a new line at the end of the
output. The only major difference between them is that endl also flushes the
output stream everytime it adds a ‘\n’ which may make the program slow because
flushing takes time
File Streams
In C++ we have a set of file handling methods. These include ifstream, ofstream,
and fstream. These classes are derived from fstrembase and from the
corresponding iostream class. These classes, designed to manage the disk files, are
declared in fstream and therefore we must include fstream and therefore we must
include this file in any program that uses files.
Whenever we open a file, it’s good practice to check if opening the file was
successful.
fout.open("outfile", ios::app);
To read more about the implementation of ifstream, ofstream, and fstream classes
in File Handling,
Stream Iterators
Advancing the iterator performs one exraction, akin to std::cin >> n; if the
extraction fails, the iterator assumes the singular state, which is also the state of
the default-constructed iterator.
Output stream iterators can be used similarly to turn a stream into a "container",
useful for algorithms that work with iterators
You can learn more about stream iterators from this article
Memory Leak
Memory leakage occurs in C++ when programmers allocates memory by using new
keyword and forgets to deallocate the memory by using delete() function or
delete[] operator. If a program has memory leaks, then its memory usage increases
very fast. Since all systems have limited amount of memory and memory is costly, it
will create problems like reduced performance, program running out of memory
and also some security vulnerabilities. However, you can prevent the issue of
memory leak if you read this article. One of the way to avoid memory leak is to use
smart pointers which we will cover below.
Smart Pointers
The implementations of these smart pointers are covered in the previous video,
however, you can also read this article for more information on them.
You can also read this article or this article which summarizes Smart Pointers.
Thread - Threads are lightweight units of execution that run within a process. They
share the same memory space as the parent process, but have their own program
counter and stack. We can implement threads using the following methods
Function Pointe
Function Object
Lambda functions
This article shows the implementation of threads in C++ using the above methods
or you can watch this video. You can also watch this video for more information.
std::thread::join blocks the current thread until the specified thread finishes its
execution whereas std::thread::detach separates the thread of execution from the
current thread, allowing execution to continue independently. Any allocated
resources will be freed once the thread exits. We could also use
std::thread::joinable to check whether a thread could be joined or detached
without any errors. To know more about the implementation watch this video or
read this article.
Thread Synchronization
Semaphore
RAII
Day 5
An extensive program or software rarely works the first time correctly. There may
be errors in this.The two most common types of errors are
Logical error
Syntactic errors
The main motive of the exception handling concept is to provide a means to detect
and report an exception so that appropriate action can be taken. This mechanism
needs a separate error handling code that performs the following tasks
Find and hit the problem (exception
Inform that the error has occurred (throw exception
Receive the error information (Catch the exception
Take corrective actions (handle exception)
Exception handling in C++ consists of three keywords: try, throw and catch.
The try statement allows you to define a block of code to be tested for errors
while it is being executed
The throw keyword throws an exception when a problem is detected, which lets
us create a custom error
The catch statement allows you to define a block of code to be executed if an
error occurs in the try block.
Output :
try-block - cppreference.com
This kind of errors are occurred, when the program is executing. As this is not
compilation error, so the compilation will be successfully done. Since these errors
are generated after your program is compiled successfully these are generally hard
to find and to get the precise line where the error is occurring is found out using
debuggers(For example GDB ) which we will discuss later
Segmentation Fault(SIGSEGV)
Segmentation fault usually occurs in a C++ program when you try to access a
memory which is does not belong to your process
You can see here the most common reasons that can lead to a segmentation fault
error
Bus Error(SIGBUS)
On the other hand Bus error is caused when you are using a processor instruction
with an address that does not satisfy its alignment requirements.
If an error itself is detected by the program then this signal is generated using call
to abort() function. This signal is also used by standard library to report an internal
error. assert() function in C++ also uses abort() to generate this signal.
You can learn about abort(), assert() and exit() in this article
Stack Overflow
All the functions are executed in a global stack in C++ so, naturally all the variables
created inside these function also reside also lie in this stack so if we try to declare
large variable inside a function that may lead to the overflow of stack
Although you can set the stack size of your program using this preprocessor
directive but this is not advisable as asking for memory more than that your RAM
can give will lead to less space for operating system programs and can lead to
unexpected shutdown of your system and repeatedly doing this may lead to some
technical complications
Heap Overflow
Although it is usually said that heap size is much more than that of stack size and
we can allocate memory dynamically in heap freely, it is not true that there is
nothing called heap overflow. If you keep allocating more and more memory in
heap without freeing the memory which is of no use now it may lead to memory
leak and would further lead to heap overflow. But this rarely happens because of
efficient memory allocation in C++. Learn more from this answer
You may notice that by default the output of both cerr and cout goes to the
terminal itself so why to use it in the first place instead of cout. The main reason is
that it gives you more control over how you handle your error stream as might be
the case that you are developing an application where you want to send all the
error messages in a log file which can be then done using cerr
Debugging in C++
You can define your own debug method which you can use while writing your
program in C++ as sometimes you want to see the values of the variables in the
middle of the program
GDB stands for GNU debugger tool and can be used for debugging C or C++ files.
Read this article to learn basics of GDB
VsCode also supports C++ debugging with a nice GUI interface which is efficient
and easy to understand. Learn more about it here
Day 6
Strings in C++
The C++ strings library includes support for three types of strings
std::basic_string - a templated class designed to manipulate strings of any
character type
std::basic_string_view (C++17) - a lightweight non-owning read-only view into a
subsequence of a string
Null-terminated strings - arrays of characters terminated by a special null
character.
The std:string class stores the characters as a sequence of bytes with the
functionality of allowing access to the single-byte character.
Stringstream in CPP
A stringstream associates a string object with a stream allowing you to read from
the string as if it were a stream (like cin). To include this feature in our code, we
need to include the sstream library.
In, sstream the standard library provides streams to and from a string:
It is very useful in parsing input. These operations are frequently used to convert
textual data types to numerical data types and the other way around.
To perform the read operation from the stringstream object we have two
different methods are present. Reading from the stringstream means getting the
data written in the object of the stringstream class for which we can
Using extraction (>>) operator: We can use the extraction operation in the
same way we use it with cin to get data from the input stream and can read
data from the stringstream object
Using the str() function: As we have seen the str() function of the stringstream
class above in the article, we can use it to get data from the stringstream class
object.
Day 7
Assembly Language
There is a general misconception among many people that there C/C++ code is first
converted into an assembly code and then converted into machine level code but
this is not true. Nowadays, compiler will just generate some assembly in memory
but then convert it to machine code themselves and only write the machine code to
file. Learn more
If you want to look at the assembly code for your C/C++ code run the following
command in terminal
You can directly write the assembly code in your C++ code using the asm
declaration. You can learn more about it here
Do try these on your system, try online compiler if not working. This may be
because of use of different os. More examples here.