Commit 6971165c authored by CHAMONT David's avatar CHAMONT David
Browse files

First set

parent 3bbea3c0
#include <iostream>
template < typename T >
class Ref {
public :
Ref( T & data ) { pdata = &data ; }
void operator=( T data ) { *pdata = data ; }
private :
T * pdata ;
} ;
template < typename T >
Ref<T> make_ref( T & data )
{ return Ref<T>(data) ; }
template < typename T >
void f( T data )
{ data = 42 ; }
int main()
{
int i = 0, j = 0 ;
f(i) ;
f(make_ref(j)) ;
std::cout<<i<<" "<<j<<std::endl ;
return 0 ;
}
#include <iostream>
template < typename T >
class Ref
{
public :
Ref( T & data ) : data_(data) {}
void operator=( T data ) { data_ = data ; }
private :
T & data_ ;
} ;
template < typename T >
Ref<T> make_ref( T & data )
{ return Ref<T>(data) ; }
template < typename T >
void f( T data )
{ data = 42 ; }
int main()
{
int i = 0, j = 0 ;
f(i) ;
f(make_ref(j)) ;
std::cout<<i<<" "<<j<<std::endl ;
return 0 ;
}
//
// Modify the class Ref, and only this class, so that
// the call to f(make_ref(j)) modify the value of j,
// while f(i) does not modify i.
// The final display should be : 0 42
//
#include <iostream>
template < typename T >
class Ref
{
public :
Ref( T data ) { data_ = data ; }
void operator=( T data ) { data_ = data ; }
private :
T data_ ;
} ;
template < typename T >
Ref<T> make_ref( T & data )
{ return Ref<T>(data) ; }
template < typename T >
void f( T data )
{ data = 42 ; }
int main()
{
int i = 0, j = 0 ;
f(i) ;
f(make_ref(j)) ;
std::cout<<i<<" "<<j<<std::endl ;
return 0 ;
}
---
# 1. Basic challenge
## What is displayed ?
```cpp
#include <iostream>
struct MyInteger
{
MyInteger( int i = 0 ) : i_(i) {}
int i_ ;
}
int main()
{
MyInteger mi() ;
std::cout<<mi.i_<<std::endl ;
}
```
1. nothing, it will fails to compile MyInteger
2. there will be an error at runtime
3. random anything
4. 0
5. nothing, it will fails to compile main()
## **Good** and *bad* answers
* **1**: the final `;` is lacking
* *3* : the only constructor of the class always set `i_` to a value ; there is no reason it may be random.
* **5**: the famous "most vexing parse" ! `MyInteger mi() ;` is interpreted as a function declaration, not an object construction.
---
# 2. A dynamic memory challenge
## May I copy such an array ?
```cpp
class Array
{
public :
explicit Array( unsigned s ) { data_ = new double [s]; }
double & operator[]( unsigned i ) { return data_[i]; }
~Array() { delete data_; }
private :
double * data_;
} ;
```
1. yes, the copy constructor is added by the compiler
2. no, the operator=() is lacking
3. no, the copy constructor is lacking
4. core dumped or segmentation fault ensured
5. yes, but there is a memory leak
6. yes, thanks to explicit
## **Good** and *bad* answers
* *1* : the implicit copy constructor is perforing a shallow copy, not relevant here.
* **2** and **3** : when dynamic rsources are involved (here heap memory), one must redefine the copy constructor, the copy assignment operator... and also now the move constructor and the move assignment operator.
* **4** : also true !
* *5* : the problem here is not memory leak, but shared memory which will be deleted several times.
* *6* : off-topic ; `explicit` is there in order to forbid an implicit compiler conversion between an `unsigned` and an `Array`.
---
# 3. About implicit conversions with predefined numerical types
## What is displayed ?
```cpp
#include <iostream>
int main()
{
int i = -1 ;
unsigned int j = 1 ;
if ( i < j ) std::cout << "i is less than j" ;
else std::cout << "i is greater than j" ;
return 0 ;
}
```
1. there will be a compilation error
2. there will be an error at runtime
3. i is less than j
4. i is greater than j
## **Good** and *bad* answers
* **4** : when interpreting `i < j`, the compiler convert all the numbers `unsigned int`, which it considers more accurate than `int`, then the value `-1` becomes the highest possibel value than an `unsigned int` can have, therefore greater than `1`. Damned !
---
# 4. An object-oriented challenge
## What is displayed ?
```cpp
#include <iostream>
struct A {
void m( double d )
{ std::cout<<d<<std::endl ; }
} ;
struct B : public A {
void m( int i )
{ std::cout<<i<<std::endl ; }
} ;
int main()
{
B b;
b.m(3.14);
return 0;
}
```
1. there will be a compilation error
2. there will be an error at runtime
3. 3
4. 3.14
## **Good** and *bad* answers
* **3** : when interpreting `b.m(3.14)`, the compiler find some `m` function within class `B`, and then does not check if the base class has some better matching function.
---
# 5. A floating point challenge
## Why is it returning false ?
```cpp
bool check()
{
float ref, index ;
ref = 169.0 / 170.0 ;
for ( index = 160.0 ; index < 170.0 ; index += 1.0 )
if ( ( index / ( index + 1.0 ) ) == ref )
return true ;
return false ;
}
```
1. never iterate with a real variable (index)
2. never compare floats with ==
3. 1.0 is a double
4. index value is never 169.0
## **Good** and *bad* answers
* *1* : one can iterate with anything iterable...
* **2** : floating operation are never perfectly exact ; any floating comparison must allow an epsilon error.
* **3** : because `1.0` is a double, the result of `index / ( index + 1.0 )` is a double, and will not match the value stored in `ref`, which is a float ; try with `1.0f`, or `static_cast<float>( index / ( index + 1.0 ) )`.
* *4* : nice try ;) actually no, because the step of `1.0` is 2 power 0, it can be exactly encoded in binary basis, and the last value of `index` will exactly be `169.0` ; if the step was `0.1`, for example, the value of ìndex` would never be exactly `169.0`.
---
# 6. A polymorphisme challenge
## What is lacking below ?
```cpp
class A
{
public :
A() {}
~A() {}
virtual void display() = 0 ;
}
```
1. one "virtual"
2. several "virtual"
3. a "private" zone
4. the body of display()
## **Good** and *bad* answers
* **1**: the destructor should be virtual, because `display()` is.
* *3* : a private zone is not mandatory.
* *4* : off-topic ; that is an abstract class, not all the functions needs to be implemented.
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Demonstration notebook\n",
"\n",
"A jupyter notebook is a sequence of cells. Some of them are for textual explanations, and written in markdown. Some of them are extracts code, and can be executed on the fly, thanks to the associated **kernel** attached to the notebook.\n",
"\n",
"The jupyter notebooks were initially designed for interpreted language, such as python, but the QuantStack company provides the [xeus-cling](https://xeus-cling.readthedocs.io/en/latest/) kernels, which extend those notebooks to C++. This notebook is associated to a C++17 kernel.\n",
"\n",
"When you use a notebook, you can interactively select any cell, *double-click* on it, and edit its content. Then, when you *shift-return*, a markdown cell will be rendered, and a code cell will be executed on the associated `kernel`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Code executed with the xeus-cling kernel\n",
"\n",
"The recent releases of xeus-cling have made huge progress, so to marry the \"compiled\" nature of C++ with the \"interpreted\" nature of notebook cells. Yet, you will encounter during this lesson some old notebooks, with tricks which were necessary with the old kernels."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You should consider all the code cells of a given notebook are subsets of a single big C++ program. In C++, one cannot declare several time the same variable. As a consequence, it was initially impossible to reuse the same variable name in several cells. It was even impossible to replay the same cell several times ! In order to bypass this limit, we often enclose each cell in a `{}` block, creating a local scope:"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"i is greater than j"
]
}
],
"source": [
"{\n",
" int i = -1 ;\n",
" unsigned int j = 1 ;\n",
" if ( i < j ) std::cout << \"i is less than j\" ;\n",
" else std::cout << \"i is greater than j\" ;\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Also, until recently, one had to make an independant cell for each independent function, and you may encounter such notebooks where we have split the code in many many cells."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Restarting the kernel\n",
"\n",
"When it fails to compile some wrong code, the kernel may switch in a *corrupted* state, being unable to compile anything more. When you suspect such a situation, **restart the kernel** with the relevant button above. This can be done any time, on purpose, when you want to restart your execution from a blank page."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Code executed in the underlying machine"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Sometimes, we want to demonstrate some modern C++ features which are not yet supported by the notebook kernel, but may be compiled with the underlying computer where your jupyter server is running. Also, sometimes, we need some additional libraries which are not accessible to the notebook kernel, or we want to split our code into several files and demonstrate how those files interact."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The cell below, with its magic first line `%%file`, will generate a file in the underlying file system, which you can see if you look at the file browser on the left of this window, or if you start a terminal."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting tmp.ref.cpp\n"
]
}
],
"source": [
"%%file tmp.ref.cpp\n",
"\n",
"#include <iostream>\n",
"\n",
"template < typename T >\n",
"class Ref\n",
"{\n",
"public :\n",
" Ref( T data ) { data_ = data ; }\n",
" void operator=( T data ) { data_ = data ; }\n",
"private :\n",
" T data_ ;\n",
"} ;\n",
"\n",
"template < typename T >\n",
"Ref<T> make_ref( T & data )\n",
"{ return Ref<T>(data) ; }\n",
"\n",
"template < typename T >\n",
"void f( T data )\n",
"{ data = 42 ; }\n",
"\n",
"int main()\n",
"{\n",
" int i = 0, j = 0 ;\n",
" f(i) ;\n",
" f(make_ref(j)) ;\n",
" std::cout<<i<<\" \"<<j<<std::endl ;\n",
" return 0 ;\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The cells below, with their magic prompt `!`, are executing bash commands in the underlying folder, and display their outputs."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"!rm -f tmp.ref.exe && g++ -std=c++03 tmp.ref.cpp -o tmp.ref.exe"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 0\n"
]
}
],
"source": [
"!./tmp.ref.exe"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "C++17",
"language": "C++17",
"name": "xcpp17"
},
"language_info": {
"codemirror_mode": "text/x-c++src",
"file_extension": ".cpp",
"mimetype": "text/x-c++src",
"name": "c++",
"version": "17"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
# Get in touch
## Who are the trainers ?
* Helper and translater : [Olga Abramkina](https://discourse.lal.in2p3.fr/u/olga/summary) (CNRS, IDRIS)
* Translater : [Pierre Aubert]() (CNRS, LAPP)
* Main lecturer : [David Chamont](https://discourse.lal.in2p3.fr/u/david/) (CNRS, IJCLab)
* Helper and translater : [Karim Hasnaoui](https://discourse.lal.in2p3.fr/u/hasnaoui/summary) (CNRS, IDRIS)
## Who are the trainees ?
## Forum check-list
* Have you created your account on the [LAL Discourse forum](https://discourse.lal.in2p3.fr/) ?
* Did you fill your profile ? ( Top right / Preferences / Preferences / Profile / About me )
* Do you watch the category [“2021 - Scientific Modern C++”](https://discourse.lal.in2p3.fr/c/formation/2021-scientific-modern-cpp/) ? ( Select the bell on the right )
## Quizz
Live only.
## Exercise
As a warm-up, we suggest you try an exercise using the web compiler [CoLiRu](http://coliru.stacked-crooked.com/) (use the `-std=c++03` option).
Copy the code below into the [CoLiRu web page](http://coliru.stacked-crooked.com/). Make sure the compiler command, at the bottom of the age, has the option `-std=c++03`. Then push the button "Compile, link and run...". The output should be `0 0`: the `f()` function takes its input argument by value, and modify the value, ont the original variable.
We would like the `make_ref()` function wrap its argument in an instance of `Ref`, in such a way that the call to `f(make_ref(j))` will really `j`. Modify the class `Ref`, and only this class, so to make that happens. The output should be `0 42`.
Play !
```cpp
#include <iostream>
template < typename T >
class Ref
{
public :
Ref( T data ) { data_ = data ; }
void operator=( T data ) { data_ = data ; }
private :
T data_ ;
} ;
template < typename T >
Ref<T> make_ref( T & data )
{ return Ref<T>(data) ; }
template < typename T >
void f( T data )
{ data = 42 ; }
int main()
{
int i = 0, j = 0 ;
f(i) ;
f(make_ref(j)) ;
std::cout<<i<<" "<<j<<std::endl ;
return 0 ;
}
```
## How to use notebooks
Once jupyter is installed on your machine, do not forget to
add the xeus-cling kernels for C++:
* `conda install -c conda-forge xeus-cling`
Then, you can start either the simple old-fashioned server,
or the more complete jupyter laboratory :
* `jupyter notebook`
* `jupyter-lab`
## If you use Docker
In case you prefer to use Docker, there is a script provided with
the course material, which helps you start a container. Within a
`bash` shell, move to the top folder of *ModernScientificCpp*,
and type :
* `./Etc/docker/run.sh modern gcc10`
Then you can start the old-fashioned server or the laboratory,
with some few additional options, required for Docker:
* `jupyter notebook --no-browser --allow-root --ip=0.0.0.0`
* `jupyter-lab --no-browser --allow-root --ip=0.0.0.0`
\ No newline at end of file
# Mise en route
## Quizz
Live only.
## Forum
* Création des comptes sur le [forum Discourse du LAL](https://discourse.lal.in2p3.fr/), en remplissant Préférences / Profil.
* Chacun se présente et relis/commente son profil.
* Surveiller la [catégorie 2020 C++ Scientifique Moderne](https://discourse.lal.in2p3.fr/c/formation/Cpp2020).
## Exercice Ref
En guise d'échauffement, nous vous proposons d'essayer un exercice en utilisant le compilateur en ligne [CoLiRu](http://coliru.stacked-crooked.com/) (utilisez l'option `-std=c++03`).
Dans le code ci-dessous, modifiez la classe `Ref`, et uniquement cette classe, de telle sorte que l'appel à `f(ref(j))` modifie la valeur de `j`, contrairement à l'appel à `f(i)`.
```cpp
#include <iostream>
template < typename Data >
class Ref
{
public :
Ref( Data data ) { data_ = data ; }
void operator=( Data data ) { data_ = data ; }
private :