Effective Code Transformations in C++

64
Effective Code Transformations in C++ Marco Arena [email protected] Paolo Polce [email protected] Reggio Emilia, 30 Novembre 2013

description

Slide del talk presentato il 30 Novembre 2013 all'Italian Agile Day a Reggio Emilia (Marco Arena & Paolo Polce)

Transcript of Effective Code Transformations in C++

Page 1: Effective Code Transformations in C++

Effective Code Transformations in C++

Marco [email protected]

Paolo [email protected]

Reggio Emilia, 30 Novembre 2013

Page 2: Effective Code Transformations in C++

2

Italian C++ Community

www.italiancpp.org

@italiancpp

Page 3: Effective Code Transformations in C++

3

Ancora evolvono il C++??!

Page 4: Effective Code Transformations in C++

4

This PLT Life - http://this-plt-life.tumblr.com/

When I hear they’re adding features to C++

Page 5: Effective Code Transformations in C++

5

Outline

• C++11, benvenuto nel team!– C++98 C++11 & snippet C#

• Il team cambia stile & coding standards– Design patterns– Multi-threaded C++

• Alcune linee guida

Page 6: Effective Code Transformations in C++

6

Outline

• C++11, benvenuto nel team!– C++98 C++11 & snippet C#

• Il team cambia stile & coding standards– Design patterns– Multi-threaded C++

• Alcune linee guida

Page 7: Effective Code Transformations in C++

7

C++ o C#?!

var dati = new List<int>(){1,2,3,4,5};

Page 8: Effective Code Transformations in C++

8

C++ o C#?!

var dati = new List<int>(){1,2,3,4,5};auto dati = vector<int>{1,2,3,4,5};

Page 9: Effective Code Transformations in C++

auto

// C++98

vector<int> vec (10);vector<int>::iterator it = vec.begin();

Page 10: Effective Code Transformations in C++

10

auto

// C++98

vector<int> vec (10);vector<int>::iterator it = vec.begin();

1 2 3 4

it

10

6 12

5 7 11 13

it

Page 11: Effective Code Transformations in C++

auto

// C++98

vector<int> vec (10);vector<int>::iterator it = vec.begin();

// C++11

vector<int> vec (10);auto it = vec.begin();

Page 12: Effective Code Transformations in C++

12

auto

// C++98

vector< pair<string, int> > cards = ... ;vector< pair<string, int> >::iterator it = cards.begin();

Page 13: Effective Code Transformations in C++

13

auto

// C++98

vector< pair<string, int> > cards = ... ;vector< pair<string, int> >::iterator it = cards.begin();

// C++11

auto it = cards.begin();

Page 14: Effective Code Transformations in C++

14

range-based iteration

// C++98

for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it)

{   cout << *it << " ";}

Page 15: Effective Code Transformations in C++

15

range-based iteration

// C++11

for (auto i : vec){

cout << i << " ";}

Page 16: Effective Code Transformations in C++

16

range-based iteration

// C++11

for (auto i : vec){

cout << i << " ";}

for (const auto& i : vec){

cout << i << " ";}

Page 17: Effective Code Transformations in C++

17

range-based iterationC++98 C++11

for ( vector<int>::iterator it = vec.begin();

it != vec.end(); ++it)

{    cout << *it << " "; }

for (auto i : vec) { cout << i << " "; }

C#

foreach (var i in arrayList) { System.Console.Write(i); }

Page 18: Effective Code Transformations in C++

18

lambdas & algorithms

// C++98

vector<int>::const_iterator find_in_range(const vector<int>& vec)

{vector<int>::const_iterator i = vec.begin();

for( ; i != vec.end(); ++i ) {

if( *i > 0 && *i < 10 ) break;}return i;

}

Page 19: Effective Code Transformations in C++

19

lambdas & algorithms

// C++98

bool elem_in_range(int elem) {

return elem > 0 && elem < 10;}

vector<int>::const_iterator it = find_if (vec.begin(), vec.end(), elem_in_range);

Page 20: Effective Code Transformations in C++

20

lambdas & algorithms

// C++11

auto it = find_if (begin(vec), end(vec), [](int i) {

return i > 0 && i < 10;});

Page 21: Effective Code Transformations in C++

21

lambdas & algorithms

// C++14

auto it = find_if (begin(vec), end(vec), [](auto i) {

return i > 0 && i < 10;});

Page 22: Effective Code Transformations in C++

22

lambdas & algorithmsC++14

[](auto i) { return i > 0 && i < 10; }

C#

(int i) => i > 0 && i < 10;

Page 23: Effective Code Transformations in C++

23

C++ o C#?!

var dati = new List<int>(){1,2,3,4,5};auto dati = vector<int>{1,2,3,4,5};

Page 24: Effective Code Transformations in C++

24

initializer lists

// C++98

int arr[] = {1,2,3,4,5};

vector<int> data;data.push_back(1);data.push_back(2);...

vector<int> data (arr, arr + 5);

Page 25: Effective Code Transformations in C++

25

initializer lists

// C++98

int arr[] = {1,2,3,4,5};vector<int> data (arr, arr + 5);

// C++11

vector<int> data = {1,2,3,4,5};// oppure (auto-everything syntax):

auto data = vector<int>{1,2,3,4,5};

Page 26: Effective Code Transformations in C++

26

initializer listsC++98 C++11

vector<int> data;data.push_back(1);data.push_back(2);data.push_back(3);...

auto data = vector<int>{1,2,3,4,5};

C#

var dati = new List<int>() {1, 2, 3, 4, 5};

Page 27: Effective Code Transformations in C++

27

smart pointers

// C++98{ Car* car = new Car(...); ... car->Move(); ... delete car;}

Page 28: Effective Code Transformations in C++

28

smart pointers

// C++98{ Car* car = new Car(...); ... car->Move(); ... delete car;}

throw exception(…)

Page 29: Effective Code Transformations in C++

29

smart pointers// C++98

 Car *car = NULL;   try {   car = new Car(...);

car->Move();      delete car;                  } catch(...) {  delete car;

ASSERT(FALSE);LOG(ERROR) << "critical";throw;            

}

Page 30: Effective Code Transformations in C++

30

smart pointers// C++98

catch(...) {  delete car;

ASSERT(FALSE);LOG(ERROR) << "critical";

throw;             }

Page 31: Effective Code Transformations in C++

31

smart pointers

{ // C++11 unique_ptr<Car> car {new Car{arg1}}; ... car->Move(); ...

} // delete automatico

// C++14auto car = make_unique<Car>(arg1)

Page 32: Effective Code Transformations in C++

32

Outline

• C++11, benvenuto nel team!– C++98 C++11 & snippet C#

• Il team cambia stile & coding standards– Design patterns– Multi-threaded C++

• Alcune linee guida

Page 33: Effective Code Transformations in C++

33

Modern C++: Factory

// C++98

IWriter* Create(...){

...return new CoutWriter(...);

}

// chiamante:

IWriter* writer = Create (...);...delete writer;

Page 34: Effective Code Transformations in C++

34

Modern C++: Factory

// C++11

unique_ptr<IWriter> Create (...){

...return unique_ptr<IWriter>(new

CoutWriter(...));}

// chiamante:

auto writer = Create(...);

Page 35: Effective Code Transformations in C++

35

Modern C++: Factory// C++98class WriterFactory{public: IWriter* Create(const string& where) { if (where == "cout") return new CoutWriter();

if (where == "dbgview") return new DbgViewWriter();if (where == " null") return new NullWriter();throw exception("where to write?");

}};

Page 36: Effective Code Transformations in C++

36

Modern C++: Factory// C++11-14class WriterFactory{public: unique_ptr<IWriter> Create(const string& where) { static map<string, function<unique_ptr<IWriter>()>> m = {

{"cout", []{return make_unique<CoutWriter>()}}, {"dbgview", []{return

make_unique<DbgViewWriter>()}}, {"null", []{return make_unique<NullWriter>()}}

}; return m.at(where)(); // può sollevare eccezione // oppure una policy diversa }};

Page 37: Effective Code Transformations in C++

37

Modern C++: RAII & DEFER

bool FileExists(const char* path){

ifstream file{path}; // file.open()

return file.is_open();} // file.close() automatico

Page 38: Effective Code Transformations in C++

38

Modern C++: RAII & DEFERvoid SomeFuntion(){

... Anything ...

Log("SomeFunction executed");}

Page 39: Effective Code Transformations in C++

39

Modern C++: RAII & DEFERvoid SomeFuntion(){

... Anything ...

Log("SomeFunction executed");}

throw exception(…)

Page 40: Effective Code Transformations in C++

40

Modern C++: RAII & DEFER

// go stylefunc SomeFuntion(){

defer func() {Log("SomeFunction executed")

}... Anything ...

}

Page 41: Effective Code Transformations in C++

41

Modern C++: RAII & DEFER

void SomeFuntion(){

defer d{ []{ Log("SomeFunction executed");

}};... Anything ...

}

Page 42: Effective Code Transformations in C++

42

Modern C++: RAII & DEFERclass defer{

function<void()> m_toExec;public:

defer(function<void()> f) : m_toExec{f} { }

~defer() {

m_toExec();}

};

Qui una versione migliore e completa: http://www.italiancpp.org/2013/07/16/defer-con-raii-lambda/

Page 44: Effective Code Transformations in C++

44

Outline

• C++11, benvenuto nel team!– C++98 C++11 & snippet C#

• Il team cambia stile & coding standards– Design patterns– Multi-threaded C++

• Alcune linee guida

Page 45: Effective Code Transformations in C++

45

Multi-Threaded C++int main(){

vector<int> vec(100000);iota(begin(vec), end(vec), 0); // 0 1 2 3 4 ...int avg = 0;

thread t1 { [&]{ avg = accumulate(begin(vec), end(vec),

0)/vec.size(); }};

auto maxEl = max_element(begin(vec), end(vec));

t1.join();

cout << "max: " << *maxEl << endl;cout << "avg: " << avg << endl;

}

Page 47: Effective Code Transformations in C++

47

Multi-Threaded C++int main(){

vector<int> vec(100000);iota(begin(vec), end(vec), 0);

auto willbeAvg = async ( [&]{ return accumulate(begin(vec), end(vec),

0)/vec.size(); }};

cout << "max: " << *max_element(begin(vec), end(vec)) << endl;

cout << "avg: " << willbeAvg.get() << endl;}

Page 49: Effective Code Transformations in C++

49

Multi-Threaded C++

future promise

Thread 1 Thread 2

v set_value(v)

get()

Page 51: Effective Code Transformations in C++

51

Multi-Threaded C++: PPL

void vector_mult(vector<double>& v, double c){

for_each( begin(v), end(v),[&](double& n) {

n *= c;}

);}

Page 52: Effective Code Transformations in C++

52

Multi-Threaded C++: PPL#include <ppl.h>using namespace Concurrency;

void vector_mult(vector<double>& v, double c){

parallel_for_each( begin(v), end(v),[&](double& n) {

n *= c;}

);}

Page 54: Effective Code Transformations in C++

54

Outline

• C++11, benvenuto nel team!– C++98 C++11 & snippet C#

• Il team cambia stile & coding standards– Design patterns– Multi-threaded C++

• Alcune linee guida

Page 55: Effective Code Transformations in C++

55

Alcune linee guida

• Devo migrare tutto subito?

– No, intanto assicurati di cosa supporta il tuo compilatore.

– Inizia migrando le cose deprecate (e.g. auto_ptr).

– Aggiungi qualche test su quello che stai modificando.

– Vale sempre il principio del boyscout…

Page 56: Effective Code Transformations in C++

56

Alcune linee guida

• Il mio compilatore non supporta alcune feature del C++11. Che devo fare?

– Se puoi, pianifica una migrazione del compilatore.

– Individua cosa potrà beneficiare del C++11 e come lo riscriveresti.

– Metti dei reminder per quando migrerai, tipo: //TO-DO-CPP11: …

Page 57: Effective Code Transformations in C++

57

Alcune linee guida

• Il miglior consiglio per usare C++11/C++14?

– Provalo!

– Il materiale di qualità sul C++ è aumentato.

– Frequenta isocpp.org

– Frequenta italiancpp.org

Page 58: Effective Code Transformations in C++

58

Marco & Paolo

Marco [email protected]://marcoarena.wordpress.com

Paolo [email protected]@paolopolce

webshell.it agileworks.it

Page 59: Effective Code Transformations in C++

59

~talk() noexcept {

answer_questions();}

Page 60: Effective Code Transformations in C++

60

~talk() noexcept {

answer_questions();}

Quanto è nerd questa slide?

Page 61: Effective Code Transformations in C++

61

Grazie!

Page 62: Effective Code Transformations in C++

62

Bonus: non-member begin/end

// C++98vector<int>::iterator it = vec.begin();int arr[] = {1,2,3,4,5}; arr.begin(); // eh ???

// C++11auto it = begin(vec);auto it = begin(arr); // ok!

Page 63: Effective Code Transformations in C++

63

Bonus: make_unique (1)

// C++14auto car = make_unique<Car>(arg1)

• auto-everything syntax• Exception-safety:

void func(unique_ptr<Car> c1, unique_ptr<Car> c2);

func(unique_ptr<Car>{new Car{}}, unique_ptr<Car>{new Car{}});

• Le istruzioni per creare i due Car* possono essere riordinate dal compilatore.

Page 64: Effective Code Transformations in C++

64

Bonus: make_unique (2)

func(unique_ptr<Car>{new Car{}}, unique_ptr<Car>{new Car{}});

Esempio di possibile esecuzione:

1. Allocazione memoria per la prima Car2. Allocazione memoria per la seconda Car3. Costruzione prima Car4. Costruzione seconda Car5. Costruzione primo unique_ptr6. Costruzione secondo unique_ptr

Che succede se 4 tira un’eccezione? Memory leak della prima Car!

Se chiamiamo due funzioni (come make_unique), il compilatore è costretto a fare 1,2,5 insieme e poi 3,4,6! Più dettagli a questo link (Sutter)