Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017

Embed Size (px)

Citation preview

2011

++: [email protected]@aligntech.com

1

ToDo: add links1

" ++: ", , C++ Russia 20172

++ 12 , 3D . Align Technology. , . , ++. 3D CAD . , .2

goo.gl/TL15Rg" ++: ", , C++ Russia 20173

3

++17

++11/14

++98High levelExpert level

Modern C++Almost the same :(

Within C++ is a smaller, simpler, safer language struggling to get outBjarne Stroustrup

" ++: ", , C++ Russia 20174

4

High level: RAII (exceptions) - STL boost

" ++: ", , C++ Russia 20175Expert level: new/delete, , , , ,

, boost: http://stackoverflow.com/q/8851670/261217

5

6Which boost features overlap with C++11?

1. , ++11 boost?6

conststd::vectorextract(conststd::vector&points){std::vectorresult;result.clear(); if(points.size()==0)returnresult; intp=0;boolfound=false;for(inti=1;i=0){result.clear();Pointnan;nan.x=sqrt(-1);nan.y=sqrt(-1);result.push_back(nan);returnresult;}if(++i>=points.size())i=0;} returnstd::move(result);}7

.7

" ++: ", , C++ Russia 20178conststd::vectorextract(conststd::vector&points){std::vectorresult;result.clear(); if(points.size()==0)returnresult; intp=0;boolfound=false;for(inti=1;i=0){result.clear();Pointnan;nan.x=sqrt(-1);nan.y=sqrt(-1);result.push_back(nan);returnresult;}if(++i>=points.size())i=0;} returnstd::move(result);}std::vectorextractRight(std::vectorpoints){usingnamespaceboost::range;usingnamespaceboost::algorithm; autoisRight=[](constPoint&pt){returnpt.x>=0;}; automiddle=adjacent_find(points,[&](auto&&pt1,auto&&pt2){return!isRight(pt1)&&isRight(pt2);}); if(middle!=points.end())rotate(points,std::next(middle)); if(!is_partitioned(points,isRight))throwstd::runtime_error("Unexpectedorder"); points.erase(partition_point(points,isRight),points.end()); returnpoints;}

8

" ++: ", , C++ Russia 20179conststd::vectorextract(conststd::vector&points){

1. No reason to return container by const value9

" ++: ", , C++ Russia 201710std::vectorextract(conststd::vector&points){

" ++: ", , C++ Russia 201711std::vectorextract(conststd::vector&points){std::vectorresult;result.clear();

1. No reason to clear container after it is default constructed11

" ++: ", , C++ Russia 201712std::vectorextract(conststd::vector&points){std::vectorresult;

" ++: ", , C++ Russia 201713std::vectorextract(const std::vector&points){std::vectorresult; if(points.size()==0)returnresult;

1. Use empty()13

" ++: ", , C++ Russia 201714std::vectorextract(const std::vector&points){std::vectorresult; if(points.empty())returnresult;

" ++: ", , C++ Russia 201715std::vectorextract(conststd::vector&points){std::vectorresult; if(points.empty())returnresult; intp=0;boolfound=false;for(inti=1;i=points.size())i=0;}

!

Similar code snippets most probably serve similar purpose, and thus needs to be represented by a single entity.28

" ++: ", , C++ Russia 201729autoappendResult=[&](intfrom,intto,boolshouldBeRight){inti=from;while(i!=to){if(isRight(points[i])!=shouldBeRight){result={Point(NAN,NAN)};returnfalse;}if(shouldBeRight)result.push_back(points[i]);if(++i>=points.size())i=0;}returntrue;}; boolsuccess=appendResult(p,q,true)&&appendResult(q,p,false);

29

" ++: ", , C++ Russia 201730autoappendResult=[&](intfrom,intto,boolshouldBeRight){inti=from;while(i!=to){if(isRight(points[i])!=shouldBeRight)throwstd::runtime_error("Unexpectedorder");if(shouldBeRight)result.push_back(points[i]);if(++i>=points.size())i=0;}}; appendResult(p,q,true);appendResult(q,p,false);

What other alternatives do we have to represent an error?30

" ++: ", , C++ Russia 201731appendResult(p,q,true);appendResult(q,p,false); returnstd::move(result);}

RVO is disabled because standard says that type of returned value and return type of function should be the same.31

" ++: ", , C++ Russia 201732appendResult(p,q,true);appendResult(q,p,false); returnresult;}

32

" ++: ", , C++ Russia 201733std::vectorextract(conststd::vector&points){std::vectorresult; if(points.empty())returnresult; autoisRight=[](constPoint&pt){returnpt.x>=0;}; autofindBoundary=[&](boolrightToLeft){for(inti=1;i=points.size())i=0;}}; appendResult(p,q,true);appendResult(q,p,false); returnresult;}conststd::vectorextract(conststd::vector&points){std::vectorresult;result.clear(); if(points.size()==0)returnresult; intp=0;boolfound=false;for(inti=1;i=0){result.clear();Pointnan;nan.x=sqrt(-1);nan.y=sqrt(-1);result.push_back(nan);returnresult;}if(++i>=points.size())i=0;} returnstd::move(result);}intp=findBoundary(false);intq=findBoundary(true);appendResult(p,q,true);appendResult(q,p,false);

33

" ++: ", , C++ Russia 201734012345612340123456

qppq012345645601pq

" ++: ", , C++ Russia 2017350123456 p

Algorithm to find first element - adjacent_find().adjacent_find() returns iterator to the first element in the pair, how to retrieve the second? How is std::next() better than it+1? How is different from ++it?35

" ++: ", , C++ Russia 2017366012345

1. Algorithm to move it to beginning rotate()36

" ++: ", , C++ Russia 2017375601234

" ++: ", , C++ Russia 2017385601234

Algorithm to check structure is_partitioned()Algorithm to detect the tail partition_point()38

std::vectorextractRight(std::vectorpoints){" ++: ", , C++ Russia 201739

1. In which scenario this signature is preferable?39

std::vectorextractRight(std::vectorpoints){usingnamespaceboost::range;usingnamespaceboost::algorithm; autoisRight=[](constPoint&pt){returnpt.x>=0;}; " ++: ", , C++ Russia 201740

std::vectorextractRight(std::vectorpoints){usingnamespaceboost::range;usingnamespaceboost::algorithm; autoisRight=[](constPoint&pt){returnpt.x>=0;}; automiddle=adjacent_find(points,[&](auto&&pt1,auto&&pt2){return!isRight(pt1)&&isRight(pt2);}); " ++: ", , C++ Russia 201741

Why do we need & in []?What exactly this lambda function correspond to?41

std::vectorextractRight(std::vectorpoints){usingnamespaceboost::range;usingnamespaceboost::algorithm; autoisRight=[](constPoint&pt){returnpt.x>=0;}; automiddle=adjacent_find(points,[&](auto&&pt1,auto&&pt2){return!isRight(pt1)&&isRight(pt2);}); if(middle!=points.end())rotate(points,std::next(middle)); " ++: ", , C++ Russia 201742

std::vectorextractRight(std::vectorpoints){usingnamespaceboost::range;usingnamespaceboost::algorithm; autoisRight=[](constPoint&pt){returnpt.x>=0;}; automiddle=adjacent_find(points,[&](auto&&pt1,auto&&pt2){return!isRight(pt1)&&isRight(pt2);}); if(middle!=points.end())rotate(points,std::next(middle)); if(!is_partitioned(points,isRight))throwstd::runtime_error("Unexpectedorder"); " ++: ", , C++ Russia 201743

std::vectorextractRight(std::vectorpoints){usingnamespaceboost::range;usingnamespaceboost::algorithm; autoisRight=[](constPoint&pt){returnpt.x>=0;}; automiddle=adjacent_find(points,[&](auto&&pt1,auto&&pt2){return!isRight(pt1)&&isRight(pt2);}); if(middle!=points.end())rotate(points,std::next(middle)); if(!is_partitioned(points,isRight))throwstd::runtime_error("Unexpectedorder"); points.erase(partition_point(points,isRight),points.end()); " ++: ", , C++ Russia 201744

std::vectorextractRight(std::vectorpoints){usingnamespaceboost::range;usingnamespaceboost::algorithm; autoisRight=[](constPoint&pt){returnpt.x>=0;}; automiddle=adjacent_find(points,[&](auto&&pt1,auto&&pt2){return!isRight(pt1)&&isRight(pt2);}); if(middle!=points.end())rotate(points,std::next(middle)); if(!is_partitioned(points,isRight))throwstd::runtime_error("Unexpectedorder"); points.erase(partition_point(points,isRight),points.end()); returnpoints;}" ++: ", , C++ Russia 201745

" ++: ", , C++ Russia 201746conststd::vectorextract(conststd::vector&points){std::vectorresult;result.clear(); if(points.size()==0)returnresult; intp=0;boolfound=false;for(inti=1;i=0){result.clear();Pointnan;nan.x=sqrt(-1);nan.y=sqrt(-1);result.push_back(nan);returnresult;}if(++i>=points.size())i=0;} returnstd::move(result);}std::vectorextractRight(std::vectorpoints){usingnamespaceboost::range;usingnamespaceboost::algorithm; autoisRight=[](constPoint&pt){returnpt.x>=0;}; automiddle=adjacent_find(points,[&](auto&&pt1,auto&&pt2){return!isRight(pt1)&&isRight(pt2);}); if(middle!=points.end())rotate(points,std::next(middle)); if(!is_partitioned(points,isRight))throwstd::runtime_error("Unexpectedorder"); points.erase(partition_point(points,isRight),points.end()); returnpoints;}std::vectorextract(conststd::vector&points){std::vectorresult; if(points.empty())returnresult; autoisRight=[](constPoint&pt){returnpt.x>=0;}; autofindBoundary=[&](boolrightToLeft){for(inti=1;i=points.size())i=0;}}; appendResult(p,q,true);appendResult(q,p,false); returnresult;}

46

" ++: ", , C++ Russia 2017470123middlefirstlast

456

47

" ++: ", , C++ Russia 201748Sean Parent: C++ Seasoning (no raw loops)

" ++: ", , C++ Russia 201749

" ++: ", , C++ Russia 201750

012345601234

" ++: ", , C++ Russia 2017510123456! rotate()!

? ?51

52templateclassWrappingIterator:publicboost::iterator_adaptor{usingBase=boost::iterator_adaptor; public:WrappingIterator()=default;WrappingIterator(Itit,Itbegin,Itend):Base(it),m_end(end),m_size(end-begin){} private:friendclassboost::iterator_core_access; typenameBase::referencedereference()const{autoit=this->base_reference();return*(it?Can we use return type deduction here?Why it is UB?52

53templateclassWrappingIterator:publicboost::iterator_facade{public:WrappingIterator()=default;WrappingIterator(Itit,Itbegin,Itend):m_begin(begin),m_size(end-begin),m_offset(it-begin){}templateWrappingIterator(constWrappingIterator&other):m_begin(other.m_begin),m_size(other.m_size),m_offset(other.m_offset){} private:friendclassboost::iterator_core_access;templatefriendclassWrappingIterator;usingBase=boost::iterator_facade;

//Coreinterfacefunctions (on the next slide)

Itm_begin;size_tm_size;size_tm_offset;};

Why we need template constructor?53

54typenameBase::referencedereference()const{return*(m_begin+(m_offset=0;}; automiddle=adjacent_find(points,[&](auto&&pt1,auto&&pt2){return!isRight(pt1)&&isRight(pt2);});

57

" ++: ", , C++ Russia 201758autoextractRight(conststd::vector&points){usingnamespaceboost::range;usingnamespaceboost::algorithm; autoisRight=[](constPoint&pt){returnpt.x>=0;}; automiddle=adjacent_find(points,[&](auto&&pt1,auto&&pt2){return!isRight(pt1)&&isRight(pt2);}); middle=middle!=points.end()?std::next(middle):points.begin(); autobegin=makeWrappingIterator(middle,points.begin(),points.end());autorotated=boost::make_iterator_range(begin,begin+points.size());

ToDo: rotated = boost::make_iterator_range(begin, end);58

" ++: ", , C++ Russia 201759autoextractRight(conststd::vector&points){usingnamespaceboost::range;usingnamespaceboost::algorithm; autoisRight=[](constPoint&pt){returnpt.x>=0;}; automiddle=adjacent_find(points,[&](auto&&pt1,auto&&pt2){return!isRight(pt1)&&isRight(pt2);}); middle=middle!=points.end()?std::next(middle):points.begin(); autobegin=makeWrappingIterator(middle,points.begin(),points.end());autorotated=boost::make_iterator_range(begin,begin+points.size()); if(!is_partitioned(rotated,isRight))throwstd::runtime_error("Unexpectedorder");

Why it is not necessary to specify std:: before is_partitioned()?59

" ++: ", , C++ Russia 201760autoextractRight(conststd::vector&points){usingnamespaceboost::range;usingnamespaceboost::algorithm; autoisRight=[](constPoint&pt){returnpt.x>=0;}; automiddle=adjacent_find(points,[&](auto&&pt1,auto&&pt2){return!isRight(pt1)&&isRight(pt2);}); middle=middle!=points.end()?std::next(middle):points.begin(); autobegin=makeWrappingIterator(middle,points.begin(),points.end());autorotated=boost::make_iterator_range(begin,begin+points.size()); if(!is_partitioned(rotated,isRight))throwstd::runtime_error("Unexpectedorder"); autoend=partition_point(rotated,isRight);

60

" ++: ", , C++ Russia 201761autoextractRight(conststd::vector&points){usingnamespaceboost::range;usingnamespaceboost::algorithm; autoisRight=[](constPoint&pt){returnpt.x>=0;}; automiddle=adjacent_find(points,[&](auto&&pt1,auto&&pt2){return!isRight(pt1)&&isRight(pt2);}); middle=middle!=points.end()?std::next(middle):points.begin(); autobegin=makeWrappingIterator(middle,points.begin(),points.end());autorotated=boost::make_iterator_range(begin,begin+points.size()); if(!is_partitioned(rotated,isRight))throwstd::runtime_error("Unexpectedorder"); autoend=partition_point(rotated,isRight); returnboost::make_iterator_range(begin,end);}

What is the next logical step to generalization?Which of these algorithms (including rotate()) benefit from random access iterator?61

" ++: ", , C++ Russia 2017620123456!

62

" ++: ", , C++ Russia 201763templateautoextractIf(Itfirst,Itlast,Predicatep){

63

" ++: ", , C++ Russia 201764templateautoextractIf(It first,Itlast,Predicatep){usingnamespaceboost::range;usingnamespaceboost::algorithm; automiddle=adjacent_find(first,last,[&](auto&&a,auto&&b){return!p(a)&&p(b);}); middle=middle!=last?std::next(middle):first;

64

" ++: ", , C++ Russia 201765templateautoextractIf(Itfirst,Itlast,Predicatep){usingnamespaceboost::range;usingnamespaceboost::algorithm; automiddle=adjacent_find(first,last,[&](auto&&a,auto&&b){return!p(a)&&p(b);}); middle=middle!=last?std::next(middle):first; autorotated=boost::join(boost::make_iterator_range(middle,last), boost::make_iterator_range(first,middle));

65

" ++: ", , C++ Russia 201766templateautoextractIf(Itfirst,Itlast,Predicatep){usingnamespaceboost::range;usingnamespaceboost::algorithm; automiddle=adjacent_find(first,last,[&](auto&&a,auto&&b){return!p(a)&&p(b);}); middle=middle!=last?std::next(middle):first; autorotated=boost::join(boost::make_iterator_range(middle,last), boost::make_iterator_range(first,middle)); if(!is_partitioned(rotated,p))throwstd::runtime_error("Unexpectedorder");

66

" ++: ", , C++ Russia 201767templateautoextractIf(Itfirst,Itlast,Predicatep){usingnamespaceboost::range;usingnamespaceboost::algorithm; automiddle=adjacent_find(first,last,[&](auto&&a,auto&&b){return!p(a)&&p(b);}); middle=middle!=last?std::next(middle):first; autorotated=boost::join(boost::make_iterator_range(middle,last), boost::make_iterator_range(first,middle)); if(!is_partitioned(rotated,p))throwstd::runtime_error("Unexpectedorder"); autoend=partition_point(rotated,p);

67

" ++: ", , C++ Russia 201768templateautoextractIf(Itfirst,Itlast,Predicatep){usingnamespaceboost::range;usingnamespaceboost::algorithm; automiddle=adjacent_find(first,last,[&](auto&&a,auto&&b){return!p(a)&&p(b);}); middle=middle!=last?std::next(middle):first; autorotated=boost::join(boost::make_iterator_range(middle,last), boost::make_iterator_range(first,middle)); if(!is_partitioned(rotated,p))throwstd::runtime_error("Unexpectedorder"); autoend=partition_point(rotated,p); returnboost::make_iterator_range(rotated.begin(),end);}

68

PROFIT!" ++: ", , C++ Russia 201769

69

Performance?RangeTraverse timestd::vector1.0Joined range of two iterator ranges

" ++: ", , C++ Russia 201770

100M elementsdoublesum=0;for(constPoint&v:range)sum+=v.x;

70

Performance?RangeTraverse timestd::vector1.0Joined range of two iterator ranges1.18

" ++: ", , C++ Russia 201771

100M elementsdoublesum=0;for(constPoint&v:range)sum+=v.x;

Additional questions for winners: rotate()? ? - N ?71

" ++: ", , C++ Russia 201772 //lambdafunctions(includinggeneric)//ternaryoperator//exceptions//transientparametersstd::vector::empty()adjacent_find()rotate()is_partitioned()partition_point()std::next();//custommake-function//templateparametersforiterators//templateparametersforpredicates//functionreturntypedeductionboost::rangeboost::algorithmboost::iterator_adaptorboost::make_iterator_range()boost::join() !

72