7. Static Variables, Method, Representation of numbers in memory, Raw C array, Non-owning pointers in C++, Classses in memory
30 May 2020 | Modern C++
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
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; }
- ClassName::MethodName(
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