for Robot Artificial Inteligence

7. Static Variables, Method, Representation of numbers in memory, Raw C array, Non-owning pointers in C++, Classses in memory

|

Static variables and methods

Static member variables of a class

  • Exist exactly once per class, not per object
  • The value is equal accross all instances
  • Must be defined in * .cpp files

    Static member functions of a class

  • Do not have an object of a class
  • Can access private members but need an object
  • Syntax for calling:
    • ClassName::MethodName()

      Static variables

      #include <iostream >
      using std::cout; using std::endl;
      struct Counted {
      Counted () {Counted::count ++; }
      ~Counted () {Counted::count --; }
      static int count; // Static counter member.
      }
      int Counted::count = 0; // Definition.
      int main () {
      Counted a, b;
      cout << "Count: " << Counted :: count << endl; //output 2
      Counted c;
      cout << "Count: " << Counted :: count << endl; //output 3
      return 0;
      }
      

Static member functions

#include <math.h>
#include <iostream>
using std::cout; using std::endl;
class Point{
public:
  Point(int x, int y) : x_{x}, y_{y} {}
  static float dist(const Point& a, const Point& b)
  {
    int diff_x = a.x_ - b.x_;
    int diff_y = a.y_ - b.y_;
    return sqrt(diff_x * diff_x + diff_y * diff_y);
  }
private:
  int x_ = 0;
  int y_ = 0;
}
int main()
{
  Point a(2, 2), b(1, 1);
  cout << "Dist is " << Point::dist(a, b) << endl;
  return 0;
}

Recalling variable declaration

  • int x = 1;
  • float y = 1.1313f; How is the number represented in the memory?

How much memory does a type need?

Example sizeof()

1 // machine specific type sizes
2 sizeof(bool) == 1 byte;
3 sizeof(char) == 1 byte;
4 // floating point types
5 sizeof(float) == 4 bytes;
6 sizeof(double) == 8 bytes;
7 sizeof(long double) == 16 bytes;
8 // integral data types
9 sizeof(short int) == 2 bytes;
10 sizeof(unsigned short int) == 2 bytes;
11 sizeof(int) == 4 bytes;
12 sizeof(unsigned int) == 4 bytes;
13 sizeof(long int) == 8 bytes;
14 sizeof(unsigned long int) == 8 bytes;

Representing integer types

#include <iostream >
using std :: cout;
int main(){
  unsigned short int k = 37;
  cout << "sizeof(" << k << ") is " << sizeof(k)
       << " bytes or " << sizeof(k) * 8 << " bits.";
//output sizeof(37) is 2 bytes or 16 bit
}

Representable intervals

Floating point numbers

#include <iostream >
using std :: cout;
int main(){
  floak k = 3.14159;
  cout << "sizeof(" << k << ") is " << sizeof(k)
       << " bytes or " << sizeof(k) * 8 << " bits.";
//output sizeof(3.141590) is 4 bytes or 32 bit
}

float vs. double

  • Same representation as float
  • double takes 8 bytes instead of 4 for float
  • Longer Exponent und Mantissa.
    • Exponent = 11 Bits instead of 8 for float
    • Mantissa = 53 Bits instead of 23 for float

      What can we represent?

Limited number of significant digits

Digits extinction

#include <cmath>
#include <iostream>
using std::cout; using std::endl;
int main () {
  float pi = M_PI;
  float big_number = 1e7;
  cout << "Pi before: " << pi << endl;
  pi += big_number ;
  pi -= big_number ;
  cout << "Pi after: " << pi << endl;
  cout << "Difference: " << M_PI - pi << endl;
  return 0;
}
  • result:
    • pi before : 3.14159
    • pi after : 3
    • difference: 0.141593

C style arrays

  • Base for std::array, std::vector,std::string
  • Indexing begins with 0!
  • Elements of an array lie in continuous memory.

Declaration

Type array_name[length];
Type array_name[length] = {n0, n1, n2, ..., nX};
Type array_name[] = { n1, n2, n3};

Arrays are simple data containers

int main () {
  int shorts [5] = {5, 4, 3, 2, 1};
  double doubles [10];
  char chars [] = {'h', 'a', 'l', 'l', 'o'};
  shorts [3] = 4;
  chars [1] = 'e';
  chars [4] = chars [2];
  doubles [1] = 3.2;
}
  • Have no methods
  • Do not explicitly store their size

Arrays and sizeof()

  • sizeof() of an array is sizeof() *
    int shortA [5] = {5, 4, 3, 2, 1};
    double longA [4] = {1.0 , 1.1, 1.2, 1.3};
    sizeof(shortA) = 20
    sizeof(shortA) / sizeof(shortA [0]) = 5
    sizeof(longA) = 32
    sizeof(longA) / sizeof(longA [0]) = 4
    

Working memory or RAM

  • Working memory has linear addressing
  • Every byte has an address usually presented in hexadecimal form, e.g. 0x7fffb7335fdc
  • Any address can be accessed at random
  • Pointer is a type to store memory addresses

Pointer

  • * defines a pointer to type
  • The pointers have a type
  • Pointer * can point only to a variable of type
  • Uninitialized pointers point to a random address nullptr

Example:

int* a = nullptr;
double* b = nullptr;
YourType* c = nullptr;

Non-owning pointers

  • Memory pointed to by a raw pointer is not removed when pointer goes out of scope
  • Pointers can either own memory or not
  • Owning memory means being responsible for its cleanup
  • Raw pointers should never own memory
  • We will talk about smart pointers that own memory later

Address operator for pointers

  • Operator & returns the address of the variable in memory
  • Return value type is ‘‘pointer to value type’’

Example:

int a = 42;
int* a_ptr = &a;

Pointer to pointer

Example:

int a = 42;
int* a_ptr = &a;
int** a_ptr_prt = &a_prt;

Pointer dereferencing

  • Operator * returns the value of the variable to which the pointer points
  • Dereferencing of nullptr: Segmentation Fault
  • Dereferencing of unitialized pointer: Undefined Behavior
#include <iostream>
using std::cout; using std::endl;
int main () {
  int a = 42;
  int* a_ptr = &a; //a_ptr pointing address of &a
  int b = * a_ptr; // b variable copy a a_ptr pointer which is pointing a address of &a
  cout << "a = " << a << " b = " << b << endl;
  * a_ptr = 13; //change value of a_ptr which is pointing a address of a
  cout << "a = " << a << " b = " << b << endl;
  return 0;
}
  • output : a = 42, b = 42 a = 13, b = 42

Uninitialized pointer

#include <iostream>
using std::cout;
using std::endl;
int main () {
  int* i_ptr; // BAD! Never leave unitialized!
  cout << "ptr address: " << i_ptr << endl;
  cout << "value under ptr: " << * i_ptr << endl;
  i_ptr = nullptr;
  cout << "new ptr address: " << i_ptr << endl;
  cout << "ptr size: " << sizeof(i_ptr) << " bytes";
  cout << " (" << sizeof(i_ptr) * 8 << "bit) " << endl;
  return 0;
}
  • result
    ptr address: 0x400830
    value under ptr: -1991643855
    new ptr address: 0
    ptr size: 8 bytes (64 bit)
    

Important of Point

  • Always initialize with a value or a nullptr
  • Dereferencing a nullptr causes a Segmentation Fault
  • Use if to avoid Segmentation Faults
    if(some_ptr ) {
    // only enters if some_ptr != nullptr
    }
    if(! some_ptr) {
    // only enters if some_ptr == nullptr
    }
    

Arrays in memory and pointers

  • Array elements are continuous in memory
  • Name of an array is an alias to a pointer:
    double ar [3];
    double* ar_ptr = ar;
    double* ar_ptr = &ar [0];
    
  • Get array elements with operator []

Careful! Overflow!

#include <iostream>
int main () {
  int ar[] = {1, 2, 3};
  // WARNING! Iterating too far!
  for (int i = 0; i < 6; i++){
    std :: cout << i << ": value: " << ar[i]
                << "\t addr:" << &ar[i] << std :: endl;
  }
  return 0;
}
  • result
    0: value: 1 addr :0 x7ffd17deb4e0
    1: value: 2 addr :0 x7ffd17deb4e4
    2: value: 3 addr :0 x7ffd17deb4e8
    3: value: 0 addr :0 x7ffd17deb4ec
    4: value: 4196992 addr :0 x7ffd17deb4f0
    5: value: 32764 addr :0 x7ffd17deb4f4
    
  • int 4 bytes(8bits * 4 = 32bits )
  • float 8 bytes(8bits * 8 = 64 bits)
  • char 1 bytes(8 bits * 1 = 8 bits)
  • double 16 bytes(8bits * 16 )

Custom objects in memory

  • How the parts of an object are stored in memory is not strongly defined
  • Usually sequentially
  • The compiler can optimize memory
class MemoryTester {
  public:
    int i;
    double d;
    void SetData(float data) { data_ = data;}
    float* GetDataAddress() { return &data_;}
  private:
    float data_;

Where is what

#include "class_memory.h"
#include <iostream>
using std :: cout; using std :: endl;
int main(){
  MemoryTester tester;
  tester.i = 1; tester.d = 2; tester.SetData (3);
  cout << "Sizeof tester: " << sizeof(tester) << endl;
  cout << "Address of i: " << &tester.i << endl;
  cout << "Address of d: " << &tester.d << endl;
  cout << "Address of_data: "
       << tester. GetDataAddress () << endl;
  return 0;
}
//output
// memory: |i|i|i|i|_|_|_|_|d|d|d|d|d|d|d|d|...
// who is who: | int i |padding| double d |...

Reference

https://www.ipb.uni-bonn.de/teaching/modern-cpp/

Cpp Core Guidelines: https://github.com/isocpp/CppCoreGuidelines

Git guide: http://rogerdudler.github.io/git-guide/

C++ Tutorial: http://www.cplusplus.com/doc/tutorial/

Book: Code Complete 2 by Steve McConnell

Modern CMake Tutorial https://www.youtube.com/watch?v=eC9-iRN2b04

Compiler Explorer: https://godbolt.org/ Gdbgui: https://www.gdbgui.com/ CMake website: https://cmake.org/ Gdbgui tutorial: https://www.youtube.com/watch?v=em842geJhfk

Fluent C++: structs vs classes: https://google.github.io/styleguide/cppguide.html#Structs_vs._Classes

Comments