Commit 94b4e02f authored by CHAMONT David's avatar CHAMONT David
Browse files

Update for PRACE 2022.

parent 98935baf
#include <cstring>
#include <iostream>
class Text
{
public :
Text()
: m_size(0),
m_data(0)
{}
Text( char const * str )
: m_size(std::strlen(str)),
m_data(m_size?(new char [m_size+1]):0)
{ if (m_size) std::copy(str,str+m_size+1,m_data) ; }
Text( Text const & t )
: m_size(t.m_size),
m_data(m_size?(new char [m_size+1]):0)
{
std::cout<<"copy constructor"<<std::endl ;
if (m_size) std::copy(t.m_data,t.m_data+m_size+1,m_data) ;
}
Text( Text && t )
: m_size(t.m_size),
m_data(t.m_data)
{
std::cout<<"move constructor"<<std::endl ;
t.m_size = 0 ;
t.m_data = 0 ;
}
Text & operator=( Text const & t )
{
std::cout<<"copy assignment"<<std::endl ;
if (this == &t) return *this ;
delete [] m_data ;
m_size = t.m_size ;
m_data = m_size?(new char [m_size+1]):0 ;
if (m_size) std::copy(t.m_data,t.m_data+m_size+1,m_data) ;
return *this ;
}
Text & operator=( Text && t )
{
std::cout<<"move assignment"<<std::endl ;
if (this == &t) return *this ;
delete [] m_data ;
m_size = t.m_size ;
m_data = t.m_data ;
t.m_size = 0 ;
t.m_data = 0 ;
return *this ;
}
~Text()
{ delete [] m_data ; }
unsigned int taille()
{ return m_size ; }
char & operator[]( unsigned int i )
{ return m_data[i] ; }
friend std::ostream & operator<<( std::ostream & os, Text const & t )
{ if (t.m_size) return os<<t.m_data ; else return os ; }
private :
unsigned int m_size ;
char * m_data ;
} ;
Text hello()
{ return "hello" ; }
Text uppercase( Text t )
{
for ( unsigned int i=0 ; i<t.taille() ; ++i )
{ t[i] = std::toupper(t[i]) ; }
return t ;
}
int main()
{
std::cout<<uppercase(hello())<<std::endl ;
return 0 ;
}
......@@ -716,114 +716,29 @@
"## Exercise\n",
"\n",
"The class below is some kind of simplified `std::string`.\n",
"* Add a move constructor and a move assignment operator.\n",
"* Check that `main()` use the move constructor.\n",
"\n",
"<!--\n",
"#include <cstring>\n",
"#include <iostream>\n",
"\n",
"class Text\n",
" {\n",
" public :\n",
" \n",
" Text()\n",
" : m_size(0),\n",
" m_data(0)\n",
" {}\n",
" \n",
" Text( char const * str )\n",
" : m_size(std::strlen(str)),\n",
" m_data(m_size?(new char [m_size+1]):0)\n",
" { if (m_size) std::copy(str,str+m_size+1,m_data) ; }\n",
" \n",
" Text( Text const & t )\n",
" : m_size(t.m_size),\n",
" m_data(m_size?(new char [m_size+1]):0)\n",
" {\n",
" std::cout<<\"copy constructor\"<<std::endl ;\n",
" if (m_size) std::copy(t.m_data,t.m_data+m_size+1,m_data) ;\n",
" }\n",
" \n",
" Text( Text && t )\n",
" : m_size(t.m_size),\n",
" m_data(t.m_data)\n",
" {\n",
" std::cout<<\"move constructor\"<<std::endl ;\n",
" t.m_size = 0 ;\n",
" t.m_data = 0 ;\n",
" }\n",
" \n",
" Text & operator=( Text const & t )\n",
" {\n",
" std::cout<<\"copy assignment\"<<std::endl ;\n",
" if (this == &t) return *this ;\n",
" delete [] m_data ;\n",
" m_size = t.m_size ;\n",
" m_data = m_size?(new char [m_size+1]):0 ;\n",
" if (m_size) std::copy(t.m_data,t.m_data+m_size+1,m_data) ;\n",
" return *this ;\n",
" }\n",
" \n",
" Text & operator=( Text && t )\n",
" {\n",
" std::cout<<\"move assignment\"<<std::endl ;\n",
" if (this == &t) return *this ;\n",
" delete [] m_data ;\n",
" m_size = t.m_size ;\n",
" m_data = t.m_data ;\n",
" t.m_size = 0 ;\n",
" t.m_data = 0 ;\n",
" return *this ;\n",
" }\n",
" \n",
" ~Text()\n",
" { delete [] m_data ; }\n",
" \n",
" unsigned int taille()\n",
" { return m_size ; }\n",
" \n",
" char & operator[]( unsigned int i )\n",
" { return m_data[i] ; }\n",
" \n",
" friend std::ostream & operator<<( std::ostream & os, Text const & t )\n",
" { if (t.m_size) return os<<t.m_data ; else return os ; }\n",
" \n",
" private :\n",
" \n",
" unsigned int m_size ;\n",
" char * m_data ;\n",
" } ;\n",
" \n",
"Text hello()\n",
" { return \"hello\" ; }\n",
"\n",
"Text uppercase( Text t )\n",
" {\n",
" for ( unsigned int i=0 ; i<t.taille() ; ++i )\n",
" { t[i] = std::toupper(t[i]) ; }\n",
" return t ;\n",
" }\n",
"\n",
"int main()\n",
" {\n",
" std::cout<<uppercase(hello())<<std::endl ;\n",
" return 0 ;\n",
" }\n",
"-->"
"* Add a move constructor and a move assignment operator. Check that `main()` use the move constructor.\n",
"* Add some display here and there, or use debugger, so to check when the move constructor is called... what do you think ?"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 2,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting tmp.move.cpp\n"
]
}
],
"source": [
"%%file 2-ObjectMove.cpp\n",
"%%file tmp.move.cpp\n",
"\n",
"#include <cstring>\n",
"#include <iostream>\n",
......@@ -898,7 +813,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 3,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -906,20 +821,29 @@
},
"outputs": [],
"source": [
"!rm -f 2-ObjectMove.exe && g++ -std=c++17 2-ObjectMove.cpp -o 2-ObjectMove.exe"
"!rm -f tmp.move.exe && g++ -std=c++17 tmp.move.cpp -o tmp.move.exe"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 4,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"copy constructor\n",
"HELLO\n"
]
}
],
"source": [
"!./2-ObjectMove.exe"
"!./tmp.move.exe"
]
},
{
......
#include <iostream>
#include <array>
template <typename T>
class my_span
{
public :
template <typename Col>
my_span( Col & c ) : m_p0{&c[0]}, m_size{c.size()} {}
T & operator[]( std::size_t indice ) { return m_p0[indice] ; }
std::size_t size() { return m_size ; }
private :
T * const m_p0 ;
std::size_t const m_size ;
} ;
void print( my_span<int> data )
{
for( std::size_t i = 0 ; i < data.size() ; ++i )
std::cout << data[i] << ' ' ;
std::cout << std::endl ;
}
int main()
{
std::array<int,5> arr { 1, 2, 3, 4, 5 } ;
print(arr) ;
return 0 ;
}
\ No newline at end of file
#include <iostream>
#include <type_traits>
#include <cassert>
class Demo
{
public:
Demo() { std::cout<<"Constructor"<<std::endl ; }
void print() { std::cout<<"Printing"<<std::endl ; }
~Demo() { std::cout<<"Destructor"<<std::endl ; }
} ;
template <typename T, std::enable_if_t<std::is_pointer_v<T>, void> * = nullptr>
using my_owner = T ;
template <typename T, std::enable_if_t<std::is_pointer_v<T>, void> * = nullptr>
class my_not_null
{
public :
my_not_null( T p ) : m_p{p} { assert(p) ; }
my_not_null & operator=( T p ) { assert(p) ; m_p = p ; return *this ; }
T operator->() { returnm_p ; }
private :
T m_p ;
} ;
int main()
{
//my_owner<Demo> d1 ; // COMPILATION ERROR: Demo is not a pointer
//my_not_null<Demo*> p1 ; // COMPILATION ERROR: p1 is not initialized
//my_not_null<Demo*> p2(nullptr) ; // COMPILATION ERROR: p2 cannot be null
my_owner<Demo *> d2 {new Demo()} ;
my_not_null<Demo *> p3 {d2} ;
//p3 = nullptr ; // EXECUTION ERROR: p3 cannot be null
p3->print() ;
delete d2 ;
}
#include <iostream>
#include <cassert>
template <typename TypeOutput, typename TypeInput>
TypeOutput my_narrow( TypeInput input )
{
auto output {static_cast<TypeOutput>(input)} ;
assert(static_cast<TypeInput>(output)==input) ;
return output ;
} ;
int main()
{
double d1 = 42 ;
int i1 {my_narrow<int>(d1)} ;
std::cout<<i1<<std::endl ;
double d2 = 3.14 ;
int i2 {my_narrow<int>(d2)} ;
std::cout<<i2<<std::endl ;
}
\ No newline at end of file
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Cpp Core Guidelines & Guidelines Support Library\n",
"\n",
"<img src=\"img/cpp_core_guidelines_logo.png\" width=60px align=\"right\"/>\n",
"\n",
"2015 : Stroustrup and Sutter formalized a draft [coding guidelines](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines), established on an \"informal\" basis with a few experts. This tends to be now the reference for good practices."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"### Goals\n",
"* Facilitate the adoption of modern C ++.\n",
"* Reference and reinforce good practices.\n",
"* Favor automatically verifiable rules, and thus promote the emergence of verification tools."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"The rules specify a header library called **Guideline Support Library (GSL)**\n",
"* [Microsoft implementation](https://github.com/microsoft/gsl) requires C++14.\n",
"* The one implemented by Martin Moene, [GSL-lite](https://github.com/martinmoene/gsl-lite), is operational starting C++98.\n",
"* Some of the GSL proposals have been incorporated into C++11/14/17/20."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"A common point to many proposals is an increase of abstraction level. Instead of just exposing the implementation and the language mechanisms used, they strive to **better express the developer's intention**."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"### To be continued\n",
"* [Pointers](en.1-gsl-pointers.ipynb)\n",
"* [Arrays](en.2-gsl-arrays.ipynb)\n",
"* [Utilities](en.3-gsl-utilities.ipynb)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"© *CNRS 2021* \n",
"*This document was created by David Chamont and translated by Olga Abramkina. It is available under the [License Creative Commons - Attribution - No commercial use - Shared under the conditions 4.0 International](http://creativecommons.org/licenses/by-nc-sa/4.0/)*"
]
}
],
"metadata": {
"celltoolbar": "Diaporama",
"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
}
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# About pointers\n",
"\n",
"Many of the problems with pointers come from their multiple uses. They point indifferently to:\n",
"* memory areas of the stack or of the heap,\n",
"* single objects or tables,\n",
"* heap zones whose release is managed elsewhere,\n",
"* heap zones to be released at the end of the current instruction block.\n",
"\n",
"**Let's sort it out and express these uses more clearly**."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Raw pointers and references: `T*` and `T&`"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"A \"raw\" pointer (e.g. `T *`) is supposed to have the most ordinary meaning: **it points to an object, but does not \"own\" it**. In what follows, the portion of code that uses this pointer is not supposed to do a `delete` at the end of the use."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"If the pointer itself is not meant to change value, and is never meant to be zero, **we will prefer a reference** whenever possible."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"In addition, using a raw pointer to designate an array is to be avoided. Many other solutions exist now."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Non-zero pointers: `gsl::not_null<T>`\n",
"\n",
"When dereferencing a pointer (via `*` or `->`), a common practice is to first check that it is not null as a precaution, which obscures and slows down the code."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"Whenever possible, **replace this pointer with a reference**."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"**Otherwise**, use **`gsl::not_null<T>`**, which ensures that you never assign a null value to the pointer."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"If you try to assign a null value, you will get an error at compile time (`d2` in the example below), or at run time (`d4` in the example below)."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting tmp.gsl-pointer.cpp\n"
]
}
],
"source": [
"%%file tmp.gsl-pointer.cpp\n",
"\n",
"#include <iostream>\n",
"#include <gsl/gsl>\n",
"\n",
"struct Demo {\n",
" Demo() { std::cout<<\"Constructor\"<<std::endl ; }\n",
" ~Demo() { std::cout<<\"Destructor\"<<std::endl ; }\n",
"} ;\n",
"\n",