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:
    1. Two threads share a vector
    2. Thread one reads the size of the vector
    3. Thread two clears the vector
    4. Thread one reads the size-1 element of the vector
    5. 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

  1. Thread one requests and acquires the lock and starts work
  2. Thread two requests the lock, but must wait until thread one releases the lock
  3. Thread one is done doing work and releases the lock
  4. Thread two now acquires the lock and does its work
  5. Thread two releases the lock

Don't forget to release locks

C++ 11 threads and mutexes

Demo and examples

Made with Slides.com