• Non ci sono risultati.

Michelangelo DiligentiIngegneria Informatica e dell'Informazionediligmic@dii.unisi.it C++11

N/A
N/A
Protected

Academic year: 2021

Condividi "Michelangelo DiligentiIngegneria Informatica e dell'Informazionediligmic@dii.unisi.it C++11"

Copied!
30
0
0

Testo completo

(1)

C++11

Michelangelo Diligenti Ingegneria Informatica e

dell'Informazione

diligmic@dii.unisi.it

(2)

C++11

Nuova revisione dello standard dopo il C++98

Stabilita nel 2011 dopo anni di lavoro

I compilatori la supportano da non molto tempo

Tantissime novita'

Nuove librerie

Nuove features

Cambia molto l'uso del linguaggio anche in cose fondamentali come il ritorno dei valori

Copriremo solo alcuni aspetti

Per un testo completo vedete risorse online o Effective Modern C++, Scott Meyers

(3)

Auto

Deduzione automatica di tipo, esempi

auto x = 0; // x intero auto x = 0.0; // x double

auto x; // ERRORE tipo non determinabile

map<string, int> mappa;

auto iter = mappa.begin(); // prendo iteratore

const map<string, int> mappa;

auto iter = mappa.begin(); // prendo iteratore const

Posso unire a const e references per forzare constness od assicurare la copia per riferimento const auto& nome = oggetto.GetNome();

(4)

Range loops

Possibile definire iterazione su contenitori senza usare gli iteratori

vector<int> v;

for (int i : v) { cout << i << endl; }

map<string, int> m;

for (std::pair<string, int> p : m) {

cout << p.first << “:“ << p.second << endl;

}

(5)

Range loops

Range loop spesso usati insieme ad auto

vector<int> v;

// accesso per valore, i e' copia dei valori nel vettore for (auto i : v) {}

map<string, int> m;

// p passato per valore, p e' copia del pair<string, int>

for (auto p : m) {

cout << p.first << “ “ << p.second << endl;

}

(6)

Range loops

Auto permette grande flessibilita', ad esempio posso forzare constness e/o copia per riferimento

vector<int> v;

for (const auto& i : v) {...} // i adesso e' const int&

map<string, int> m;

// Accesso per const reference a std::pair<const std::string, int>

for (const auto& p : m) {

cout << p.first << “ “ << p.second << endl;

}

(7)

Braced initialization

C++98 inconsistente nella gestione delle inizializzazioni int i = 0;

int i(0); // come sopra vector<int> v(10);

vector<int> v = vector<int>(10); // come sopra

C++11 possibile inizializzare gli oggetti in modo consistente tramite {}

int i{0};

vector<int> v{10};

// Array const con 5 elementi subito inizializzati const float* vec = new const float[5]{1,2,3,4,5};

(8)

Braced initialization

Permette di fare anche inizializzazioni complesse

Liste di parametri nel caso generale (vi rimando al testo per questo)

Le seguenti sono inizializzazioni valide in C++11

Inizializzare un vettore di 5 interi vector<int> v = {3,2,1,5,4};

mappa con 2 valori iniziali

map<string,int> m = {{"C++98",1998}, {"C++11",i}};

(9)

nullptr vs NULL

In C++98 NULL e' semplicemente

#define NULL 0

NULL puo' essere interpretato come un intero

Non ha un tipo esplicito

Il seguente codice compila (al massimo puo' dare un warning il compilatore)

int i = NULL + 4;

C++11 specifica nullptr che non e' convertibile in un intero

Si usa come NULL Class * c = nullptr;

if (c == nullptr) { … }

(10)

Deleted methods

In C++98 si evita la copia di un oggetto definendo costruttori di copia e operator= come privati

private:

Pippo(const Pippo&) {}

Pippo& operator=(const Pippo&) {} …

In C++11 si specifica che tali metodi sono deleted

public:

Pippo(const Pippo&) = delete;

Pippo& operator=(const Pippo&) = delete;

(11)

Default methods

Possibile dire al compilatore in modo esplicito quali metodi esso deve generare

Applicabile a default, copy e move (vederemo cosa sia) construtor, destructor, operator=

class Pippo {

Pippo(int a) { … }

// Default constructor non sarebbe generato dal

// compilatore perche' c'e' Pippo(int), ma dico di generarlo

Pippo() = default;

Pippo(const Pippo& p) = default;

};

(12)

Constructor Delegation

In C++98 si puo' invocate un costruttore del padre in pre-run, ma

Non si puo' invocare altro costruttore della classe

Problema: Non si riusa codice dei costruttori

In C++11 possibile chiamare pre-run altri costruttori

Riutilizzo del codice possibile anche per i costruttori class Pippo {

Pippo(const int a) { … } Pippo() : Pippo(0) {…}

Pippo(const float b) : Pippo(static_cast<int>(b)) {…}

};

(13)

Inizializzazione in-class

Possibile inizializzare i dati membri in fase di

dichiarazione senza dover passare dal costruttore

Finalmente! Codice chiaro, leggibile e sicuro

Non rimane mai qualcosa di non inizializzato class Pippo {

string* s = nullptr;

const static int x = 5;

int y = 5; // o int y{5};

vector<int> myVec{1,2,3,4,5};

};

(14)

Lambda functions

Funzioni senza nome create nel posto dove servono

Esempio sort vettore in C++98

struct Comparator {

bool operator()(int v, int w){ return v > w; } };

sort(vec.begin(), vec.end(), Comparator());

In C++11 con lambda function:

sort(vec.begin(),vec.end(), [](int v,int w){ return v > w; });

(15)

Lambda functions

Lambda function: sintassi

[variabili_catturate](argomenti) { … la funzione … }

Variabili catturate sono le variabili locali nel chiamante che sono usate nella lambda

Default passate per valore. Possibile passarle per reference per prendere il risultato: Esempio:

vector<int> v{1,2,3,4,5};

int sum = 0;

// sum passata per reference dal contesto locale. Valore di sum dopo la // chiamata = 15 (1+2+3+4+5)

for_each(v.begin(),v.end(),[&sum](int v){sum += v;});

// sum passato per copia, suo valore resta 0 esternamente for_each(v.begin(),v.end(),[sum](int v){sum += v;});

(16)

Move semantics

Passo fondamentale del C++11

Evita il problema del C++98 della copia dei dati locali di una funzione o metodo!

Esempio ritornare una matrice grande

C++98

Matrix* Alloca(); // puntatore, poi devo deallocare

void Alloca(Matrix*); // OK ma poco naturale

C++11

Matrix Alloca(); // posso evitare la copia!

Move semantic permette di definire come spostare

un dato da una variabile temporanea ad un'altra

(17)

Move semantics: lvalue, rvalue

lvalue: valore di cui posso prendere indirizzo

permanente rispetto all'espressione valutata

rvalue: valore che esiste solo durante la valutazione dell'espressione

Esempio 1:

int x = 1; // x lvalue, 1 rvalue

(18)

Move semantics: lvalue, rvalue

Esempio 2:

Matrix Alloca() {

Matrix m(100,100);

return m; // m e' variabile temporanea, rvalue }

Esempio 3

static Matrix m;

Matrix Alloca() { m.Init(100, 100);

return m; // m statica e permanente, lvalue }

(19)

Move semantics: reference &

Reference classica & e' applicabile solo a lvalues

Matrix& Alloca() { Matrix m(100,100);

// disastro in vista, riferimento a rvalue che viene distrutto

return m;

}

static Matrix m;

Matrix& Alloca() { m.Init(100, 100);

return m; // m statica e permanente, riferimento OK }

(20)

Move semantics: &&, move constructor

Reference && solo applicabile ad rvalues

Posso specificare una specie di copy constructor per rvalues

rvalue e' temporaneo non serve fare una vera operazione di copia ma solo di spostamento!

Per oggetti grandi tale operazione e' spesso molto piu' rapida

Move constructor: invocato se si passa per valore un rvalue

class Pippo {

Pippo(const Pippo& p) { … } // copy constructor Pippo(Pippo&& p) { … } // move constructor

};

(21)

Move semantics: &&, move constructor

Esempio di move constructor

class Matrix { …

int N, M;

float* data;

Matrix(Matrix&& m) { // move constructor N=m.N; M=m.M;

// La rappresentazione dell'rvalue viene “rubata”, e si // riutilizza la memoria precedentemente allocata.

data = m.data;

m.data = nullptr; m.N=m.M=0; // svuotare il vecchio matrix }

};

Esempio di utilizzo

Matrix Alloca() {

Matrix m(100, 100);

return m; } Matrix m = Alloca();

Si ritorna l'rvalue per valore, compilatore invoca il move constructor. Massima velocita' e pulizia dell'interfaccia.

(22)

Move semantics: &&, move constructor

Move constructor veloce vs Copy constructor lento

class Matrix { …

Matrix(Matrix&& m) { // move constructor N=m.N; M=m.M;

// La rappresentazione dell'rvalue viene “rubata”, si copia // solo 1 puntatore data = m.data; m.data=nullptr; m.M=m.N=0;

}

Matrix(const Matrix& m) { // copy constructor N=m.N; M=m.M;

// Assumo implementazione con singolo vettore contiguo data = new float[N*M]; // devo riallocare, lento!

for (int i = 0; i < N*M; ++i) // copia elemento ad elemento data[i] = m.data[i];

} ...

(23)

Move semantics: contenitori

Contenitori stl copiano in inserimento

std::move() trasforma una lvalue in un rvalue

Permette di chiamare move semantics in inserimento!

C++98

vector<string> v;

string s(“ciao”);

v.push_back(s); // v prende una copia di s cout << s; // stampa “ciao”

C++11: Move semantics permette di evitare la copia

vector<string> v;

string s(“ciao”);

v.push_back(std::move(s)); // s “rubata” dal contenitore

cout << s; // stampa “”, la rappresentazione di s e' stata rubata ed e' in v

std::move(s) crea string&&

Compilatore invoca il move constructor

(24)

Move semantics: &&, move constructor

std::move usabile in ogni contesto ad esempio nel caso precedente di move constructor

class Matrix { …

int N, M;

float* data;

Matrix(Matrix&& m) : data(std::move(m.data)) { // move constructor N=m.N; M=m.M;

m.data=nullptr;

m.N=m.M=0;

} };

(25)

Librerie: smart pointers

std::unique_ptr puntatore con ownership unica

#include <memory>

{

std::unique_ptr<int> ptr(new int(42));

std::cout << ptr.get() << std::endl; // indirizzo std::cout << *ptr << std::endl; // 42

std::unique_ptr<int> second = first; // compile error // ptr distrutto automaticamente qui

}

(26)

Librerie: smart pointers

std::shared_ptr puntatore con ownership multipla

Implementa garbage collector locale

#include <memory>

{

std::shared_ptr<int> ptr1(new int);

std::cout << ptr1.use_count() << std::endl; // 1 std::shared_ptr<int> ptr2(ptr1);

std::cout << ptr1.use_count() << std::endl; // 2 std::cout << ptr2.use_count() << std::endl; // 2 }

(27)

Librerie: contenitori associativi

Contenitori associativi non ordinati

Hash tables

Permettono ricerche in O(1)

In particolare:

unordered_set<T>

unordered_multiset<T>

unordered_map<K,V>

unordered_multimap<K, V>

(28)

Librerie: contenitori

array<T>

Vettore a dimensione fissa

Stessa interfaccia di vector (anche come iteratori, e quindi algoritmi chiamabili, ecc)

array<int, 5> a{{1,2,3,4,5}};

int sum = 0;

for_each(a.begin(),a.end(),[&sum](int e){sum+=e;});

(29)

Librerie: tuple

std::tuple<T1, T2, T3, ...>

Estendono i std::pair<T1, T2> del C++98

Contenitore eterogeneo di dimensione fissa // Costruttore

std::tuple<std::string,int,float> t{"ciao", 10, 5.1};

// come make_pair per la tupla. Deduce i tipi in // modo automatico

auto t = std::make_tuple(100, "ciao", 2011,'c');

// Prende un elemento della tupla std::cout << get<2>(t);

(30)

Molte altre cose

Ottimizzazione: constexpr

Template flessibili:

alias vs typedef, variadic templates, decltype

Enum tipati: scoped enum

Controllo sull'ereditarieta': final, override

Librerie

regular expressions, multithreading support

Moderne librerie per time e numeri casuali

Utilita' generiche: static_assert, raw strings

ecc.

Riferimenti

Documenti correlati

Si dichiara l’avvenuta regolare pubblicazione della presente deliberazione all’Albo Pretorio on-line di questo Comune a partire dal 20/09/2017 per 15 giorni consecutivi, ai sensi

RITENUTO pertanto di dare avvio alla procedura per l’affidamento diretto di cui all’ art. il fine della presente procedura è rappresentato dall’esigenza di

Tale certificazione dei redditi di lavoro dipendente, equiparati ed assimilati, che attestano l’ammontare complessivo delle somme e dei valori percepiti, delle ritenute subite

1. Di prendere atto della rendicontazione presentata dall’Istituto Comprensivo di Tavernola Bergamasca dalla quale emerge che l’Istituto Comprensivo di Tavernola

Tessuto caratterizzato dalla presenza di edifici isolati su lotto con prevalente destinazione residenziale a bassa densità (ville monofamiliari e ville a schiera) con una

Copia per usi amministrativi e per la pubblicazione all’Albo Pretorio online. L’originale della presente deliberazione è depositato agli atti d’ufficio.. compresa,come da attestazione

[r]

196 del 30.6.2003 e ss.mm.ii: I dati sopra riportati sono prescritti dalle disposizioni vigenti ai fini del procedimento per il quale sono richiesti e verranno