More C++
Today's hodgepodge
- Containers
- Debugger
- Function Stack
- Pointers and dynamic memory
- Concurrency
Data Containers
- Many containers are part of the C++ STL
- http://en.cppreference.com/w/cpp/container
- e.g. STL vector
- They use templates to be able to store any type of data internally (they will even accept user created classes and types)
#include <vector>
int main(int argc, char *argv[])
{
std::vector<int> fib;
fib.push_back(1);
fib.push_back(1);
for (int i = 0; i < 10; i++) {
fib.push_back(fib[fib.size() - 1)] + fib[fib.size() - 2)];
}
}
The Debugger
- Is a program that can run a program
- And interrupt it at will
- The program needs to be compiled in a special way
- So it includes debugging symbols
- (i.e. the link between the binary and the code)
- The debugger allows analyzing memory contents while a program is running
- This helps find problems and fix crashes
The function stack
- When functions are called they are "pushed" in the function stack (this is the same stack that holds stack memory)
- When they return they are "popped" from the stack
Dynamic memory
- The stack
- Fixed size
- "static" allocation
- For known and inmutable
variable types
- The heap
- Dynamic allocation
- At runtime
- There is a memory "pool"
from which memory is
requested
Stack memory
int a;
int func(int b, int c)
{
int num;
return num * b * c * a;
}
The stack here has space for 5 floats!
Before the heap...
Pointers
- Pointers are a type
- They hold a memory address
- To a memory of a particular type
Pointers
int *a;
int b = 5;
a = &b;
*a = 10; // Now b is 10
- Are identified by an asterisk after a type
- Are set from an existing memory allocation
- Or through heap allocation
- The & operator gets the address of variables
- The * operator gets the "contents"
Pointers
int *a;
int b = 5;
a = &b;
float *c;
c = (float *) a; // Valid but weird results!
- Memory pointers can be "cast"
- i.e. they can be interpreted as something else
- After all memory is just bytes
- and a data "type" is just a way to interpret them
Why would someone devise such a contrived thing as pointers?
- Save memory and copying operations
- When passing data to a function using pointers there is no copying of data happening (only the pointer address is copied)
- So there is no extra memory used and no extra time to copy the memory contents
- Allow modifying data in a caller function
- Allow the sharing of data by various parts of the programs (e.g. threads)
- Write to hardware buffers (e.g. audio card buffers)
Arrays in C are pointers
- The memory holding the array elements is contiguous
- You can use the [] operators to access elements
- Or pointer arithmetic
char st[] = "hello"; // The size of this array is determined from the content
st[4] = '!';
char *c = st;
for (int i = 0; i < 5; i++)
{
printf("%i - %c\n", c++, st[i]);
}
Now back to the heap
Dynamic memory
(in C)
int *list = (int *) malloc(4 *sizeof(int));
list[0] = 1;
list[1] = 2;
list[2] = 3;
list[3] = 4;
list[4] = 5; // Invalid memory access!!
free(list); // You must free memory yourself
Dynamic memory
(in C++)
ClassType *variable = new ClassType;
delete variable; // You must free memory yourself
The constructor is called on "new"
The destructor is called on "delete"
Dynamic memory
(in C++)
unique_ptr : a self-destroying pointer
http://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr
In other dynamic memory scope doesn't affect the lifetime of the pointer memory, which can lead to memory leaks.
Workshop
- Write a class called GoldenRatio that inherits from Fibonacci and calculates the golden ratio from a Fibonacci sequence
- The class should "hide" the Fibonacci functions and only provide functions to
- Set the number of elements in the Fibonacci sequence
- Return the Golden Ratio
- Calculate and return the error (in percentage) from the estimation to the actual Golden Ratio
- In the main function create an object of type GoldenRatio and print the estimated value and the error
Concurrency
- Modern computer architectures are often made of multiple processors
- This means that each can "concurrently" process data
The dining philosophers
https://en.wikipedia.org/wiki/Dining_philosophers_problem#/media/File:Dining_philosophers.png
The dining philosophers
- Each philosopher must alternately think and eat.
- A philosopher can only eat spaghetti when he has both left and right forks.
- Each fork can be held by only one philosopher and so a philosopher can use the fork only if it is not being used by another philosopher.
- After he finishes eating, he needs to put down both forks so they become available to others.
- A philosopher can take the fork on his right or the one on his left as they become available, but cannot start eating before getting both of them.
From: https://en.wikipedia.org/wiki/Dining_philosophers_problem
The philosophers starve
Threads
- Are a single function
- That gets executed "asynchronously"
- i.e. as a separate thing
- You can wait for threads by attempting to "join" them
- You have to build mechanisms to signal a thread to finish (if it doesn't do it by itself, i.e. it's an "endless" loop)
Uses of threads
-
Offload computation to the "background"
- To keep UI responsive
- To create "listeners"
- e.g. Network port servers
- To parallelize applications or processes
- There are other more sophisticated uses...
The problem with threads are the forks
- Not the repository forks, but the philosophers' forks
- i.e. the things that threads need to share with others
Concurrent access to data
- Access to data simultaneously from different threads is dangerous:
- Two threads share a vector
- Thread one reads the size of the vector
- Thread two clears the vector
- Thread one reads the size-1 element of the vector
- CRASH!
- This is just a simple example, but there are many cases where threads can cause serious issues when sharing data
- But sharing data between threads is a big necessity.
Protecting data
- There are various mechanisms to protect data
- They can ensure exclusive access to data
- Mutex (the most common)
- (Mutually exclusive access)
- Also known as locks
- Semaphores and others
The forks are the protections
- The philosphers' forks are the "protection" of simultaneous data
- When the philosphers don't synchronize themselves and starve, a "race condition" occurs
Mutex
- Thread one requests and acquires the lock and starts work
- Thread two requests the lock, but must wait until thread one releases the lock
- Thread one is done doing work and releases the lock
- Thread two now acquires the lock and does its work
- Thread two releases the lock
Don't forget to release locks
C++ 11 threads and mutexes
Demo and examples
More C++
By mantaraya36
More C++
- 1,490