Top Banner
l in the Craft and prevent RSI Stoyan Damov, founder and co- owner, CSGW Ltd. [email protected] ttp://www.boost.org/
61

Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. [email protected]

Dec 26, 2015

Download

Documents

Albert Green
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Excel in the Craft and prevent RSI with

Stoyan Damov, founder and co-owner, CSGW Ltd.

[email protected]://www.boost.org/

Page 2: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

The evolution of a C++ programmerReads a “Teach yourself C++ in 60 seconds” book

Decides he knows C++, adds C++ to his CV

Reads Bjarne Stroustrup's "The C++ Programming Language" vol. 1

Decides he now knows C++, adds “extensive C++ knowledge”

Reads Bjarne Stroustrup's "The C++ Programming Language" vol. 2

Writes “C++ expert” in his CV

Reads Scott Meyers's “Effective C++” and “Effective STL”

Replaces “expert” with “guru”

Reads Herb Sutter's “Exceptional C++”

Realizes “guru” is too much, replaces “guru” with “proficient in C++”

Reads Andrei Alexandrescu's “Modern C++ Design”

Depressed, replaces “proficient” with “experienced”

Reads dozens of C++ books, finds Boost, comp.lang.c++(.moderated)

Realizes he now knows how to use C++ (and brings back “proficient”)

Page 3: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Experts and gurus are free togo out and enjoy the swimming pool

Page 4: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Excel in the Craft and prevent RSI with

"...one of the most highly regarded and expertly designed C++ library projects in the world.“

Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Page 5: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.Bind

Boost.Member Function

Boost.Ref

Boost.SmartPtr

Петър Димов

Page 6: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

#1. Pure laziness. “N more libs to learn, why?”I hope you’ll be convinced that learning and usingBoost will actually help you work less.

#2. “Haven’t checked, but my compiler probablycan’t compile it.”You’ll see it’s far from the truth even if you’re stuckwith MSVC 6.

#3. Sheer ignorance: “Who gives a @#$%?”Apparently doesn’t apply to all of you who attendthis lecture :)

Top 3 reasons Boost is ignored

Page 7: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

You’ll type less code. I’ll show you.Makes C++ a more compelling language by overcoming language and library limitations.

Drives the language (10 libs in TR1, more will be in TR2) and compilers.Extends and works well with the Standard Library.

Portable across enough compilers and OS-es.

Free and non-proprietary.

Used by top software companies like Adobe, SAP, Real Networks, McAffee, (ahem) CSGW, etc.

Some reasons to use Boost

Page 8: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

This lecture will introduce you toBoost and teach you how to:

Simplify object lifetime management and resource sharing with Boost.SmartPtr

Define function objects at call site and bind arguments to N-arity free functions, member functions and functors with Boost.Bind and Boost.Lambda

Define, store and implement callbacks with Boost.Function

Trigger and handle events (multicast callbacks) with Boost.Signals

Page 9: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

This lecture will introduce you toBoost and teach you how to:

Store and retrieve values of any type with Boost.Any and Boost.Variant

Process text efficiently with Boost.Tokenizer, Boost.StringAlgo, Boost.Regex, Boost.Xpressive and Boost.Spirit

Write portable multithreaded code with Boost.Thread

Marshal and unmarshal objects in a versioned and platform-independant manner with Boost.Serialization

Use specialized containers when STL's are not (efficient) enough from Boost.MultiArray, Boost.MultiIndex and Boost.Intrusive

Page 10: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

void leak_memory_recipe(){

T* p(new T());if (some_condition){

return;}delete p;

}

void shoot_your_self_in_the_foot(){

T* p(new T());free(p); // might launch Tetrisdelete p;delete p; // might format HDD

U* q(new U[42]);delete q; // might work in MSVC :)

void* p = malloc(sizeof(A));A* a = new(p) A();delete a; // might launch PacMan

}

Raw Pointers 1011

Page 11: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

void contrived_example(){

// Windows Mobile -- thread stack is 8K:// allocate on heap to prevent stack overflow

T* p(new T());if (!foo(p->something())){

delete p; return; // slides suck}U* q(new U());if (!bar(“bar”, q)){

delete p; delete q; return;}p->do_something_useful_with(q);delete p;q->do_something_less_useful();delete q;

}

Raw Pointers

// today

bool bar(char const* p, U* u);

• Ugly• Error-prone

Can leak p & q in 3 different ways tomorrow. How?

// tomorrow

bool bar(Bar const& bar, U* u) throw (...);

struct Bar{ Bar(std::string const& s) throw (...);};

2

Page 12: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Dumb Pointerstemplate <typename T>struct dumb_ptr{

explicit dumb_ptr(T* p) : p_(p) {}~dumb_ptr() { delete p_; }

private: // non-copyable “stuff” omittedT* p_;

};

void hand_crafted_dumb_pointers(){

T* p(new T()); dumb_ptr<T> g1(p);if (!foo(p->something())){

return;}U* q(new U()); dumb_ptr<U> g2(q);if (!bar(“bar”, q)){

return;}p->do_something_useful_with(q);q->do_something_less_useful();

} // at end-of-scope, g1 and g2 delete pointees

3

Page 13: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Smart Pointers

void enter_auto_ptr(){

auto_ptr<T> p(new T());if (!foo(p->something())){

return;}auto_ptr<U> q(new U());if (!bar(“bar”, q)){

return;}p->do_something_useful();q->do_something_less_useful();

} // at end-of-scope, p and q delete pointees

// auto_ptr defined in <memory>

4

Page 14: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Smart Pointersstruct S{

// ...private:

auto_ptr<T> p_;};

// Q: who owns T*? (hint: elipsis are misleading)

struct S{

auto_ptr<T> good_bye(){

return p_;}T* farewell(){

return p_.release();}

private:auto_ptr<T> p_;

}; // A: whoever calls good_bye or farewell first

auto_ptr<T>

• sole ownership• transferable ownership• intention hard to guess

auto_ptr<T>

• sole ownership• transferable ownership• intention hard to guess

5

Page 15: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Smart Pointersvoid launch_tetris(){

auto_ptr<char> buffer(new char[42]);};

auto_ptr<T>

• sole ownership• transferable ownership• intention hard to guess• can’t be used with arrays

auto_ptr<T>

• sole ownership• transferable ownership• intention hard to guess• can’t be used with arrays

6

Page 16: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Smarter Pointersstruct S{private:

boost::scoped_ptr<T> p_;};

// It’s all in the name: S owns T*

scoped_ptr<T>

• sole ownership• non-transferable ownership• intention at first glance

scoped_ptr<T>

• sole ownership• non-transferable ownership• intention at first glance

template <class T> class scoped_ptr : noncopyable{

...// no release() function

}

7

Page 17: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

void launches_tetris_as_well(){

scoped_ptr<char> buffer(new char[42]);};

Smarter Pointers

template <class T> class scoped_array : noncopyable{

...}

void foo(){

scoped_array<char> buffer(new char[42]);}

scoped_ptr<T>

• sole ownership• non-transferable ownership• intention at first glance• cannot be used with arrays but:

scoped_ptr<T>

• sole ownership• non-transferable ownership• intention at first glance• cannot be used with arrays but:

8

Page 18: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Raw Pointers (again)// every non-trivial multithreaded application// passes data between threads

void who_deletes_the_pointer(){

T* p(new T());launch_thread_and_pass_it(p);p->do_something_useful();

}

Кой, я ли не моа?

9

Page 19: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Reference-counted pointersstruct T : private noncopyable{

T() : refs_(1) {}void add_ref() { ++refs_; }void release(){

if (--refs_ == 0){

delete this;}

}void do_something_useful() { ... }

private:size_t refs_;

};

// continued on next slide…

10

Page 20: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

void who_deletes_the_pointer(){

T* p(new T()); // refs_ == 1launch_thread_and_pass_it(p); // refs_ == 2p->do_something_useful();

/*a*/ p->release(); // refs_ == 1 or 0?}

void launch_thread_and_pass_it(T* p){

p->add_ref(); // refs_ == 2// actually launch thread and pass it p

}

void thread(T* p){

// refs_ == 2 or 1p->do_something_useless();

/*b*/ p->release(); // refs_ == 1 or 0?}

Pray these don’t throwOR

abuse try/catch constructs

Ugly, scattered, error-prone reference

counting

Reference-counted pointers11

Page 21: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

launch_thread_and_pass_it(p); // refs_ == 2

void who_deletes_the_pointer() // thread 1 (T1)/*a*/ p->release();

void thread(T* p) // thread 2 (T2)/*b*/ p->release();

Multithreading 101: Race conditions1. refs_ = 2; (memory)2. Main thread (T1) reads the value of refs_ from memory into register 1 (r1) : 23. Secondary thread (T2) reads the value of refs_ from memory into register 2 (r2) : 24. T1 decrements the value of refs_ in r1: (r1 contents) - 1 = 15. T2 decrements the value of refs_ in r2: (r2 contents) - 1 = 16. T1 stores the value of r1 in memory : 17. T2 stores the value of r2 in memory : 18. refs_ = 1; (memory)

Pointer leaked.

Reference-counted pointers12

Page 22: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

struct T : private noncopyable{

T() : refs_(1) {}void add_ref(){

impl_atomic_increment(refs_);}void release(){

if (impl_atomic_decrement(refs_) == 0){

delete this;}

}private:

implementation-specific refs_;};

Almost there: thread-safeReference-counted pointers

13

Page 23: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

boost::shared_ptrtypedef boost::shared_ptr<T> Ptr;

void last_shared_ptr_deletes_the_pointer(){

Ptr p(new T());launch_thread_and_pass_it(p);p->do_something_useful();

}

void launch_thread_and_pass_it(Ptr p){

// launch thread and pass it p}

void thread(Ptr p){

p->do_something_useless();}

shared_ptr<T>

• shared ownership• thread-safe• cannot be used with arrays butshared_array<T> can.

shared_ptr<T>

• shared ownership• thread-safe• cannot be used with arrays butshared_array<T> can.

14

Page 24: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

A few well-known conceptsCopyConstructible

struct T{ T(T const& other);};

Assignablestruct T{ T& operator=(T const& other);};

NonCopyablestruct S{private: T(T const& other); // not CopyConstructible T& operator=(T const& other); // not Assignable};

15

Page 25: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Why do I want to know these?

Standard Library Containers require thetemplate parameter used for the containers’element type to be both CopyConstructible

and Assignable.

auto_ptr<T>, scoped_ptr<T>, andscoped_array<T> do not meet theserequirements and so cannot be used inSTL containers.

16

Page 26: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

STL containers with raw pointersstruct Big { ... };

struct T{

// ...~T();

private:// Big is expensive to copy, use pointerstypedef std::vector<Big*> BigItems;typedef BigItems::iterator iterator;BigItems items_;

};

T::~T // don’t forget to delete the pointers!{

iterator e(items_.end());for (iterator b(items_.begin()); b != e; ++b){

delete *b;}

}

17

Page 27: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

STL containers with raw pointerstemplate <typename C>void clear_container(C& c){

std::for_each(c.begin(), c.end(), Deleter());}

struct Deleter{

template <typename T>void operator()(T const* p) const{

delete p;}

};

T::~T{

clear_container(items_);}

operator() is member template so Deleter

can deduce its argument

18

Page 28: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

STL containers with shared_ptrstruct Big { ... };

struct T{private:

typedef boost::shared_ptr<Big> BigPtr;typedef std::vector<BigPtr> BigItems;BigItems items_;

};

No, really, that’s it :)

19

Page 29: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

More STL containers withraw pointers

struct Big { ... /* defines operator< */ };

struct T{private:

struct BigPtrLess{

bool operator()(Big const* l,Big const* r) const

{return *l < *r;

}};typedef std::set<Big*, BigPtrLess> BigItems;BigItems items_;

};

20

Page 30: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

More STL containers withshared_ptr (déjà vu)

struct Big { ... /* defines operator< */ };

struct T{private:

typedef boost::shared_ptr<Big> BigPtr;typedef std::set<BigPtr> BigItems;BigItems items_;

};

struct Big { ... };

struct T{private:

typedef boost::shared_ptr<Big> BigPtr;typedef std::vector<BigPtr> BigItems;BigItems items_;

};

shared_ptr defines relational operators so

pointers work as desired

21

Page 31: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

shared_ptr in a nutshell

• shared ownership - underlying pointer deleted when the lastshared_ptr pointing to it is destroyed or reset

• copy-constructible and assignable, so can be used inSTL containers

• comparison operators are defined, so can be used inassociative containers

• part of TR1• eliminates explicit deletes in code• decreases the need for try/catch constructs• thread-safe

What’s not to like?!

22

Page 32: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

struct Source;typedef shared_ptr<Source> SourcePtr;

struct Sink{ virtual void event_occurred() = 0;};typedef shared_ptr<Sink> SinkPtr;

struct Source{ virtual void set_observer(SinkPtr observer) = 0;};

struct SourceImpl : Source, private noncopyable{ void set_observer(SinkPtr observer);private: SinkPtr observer_;};

shared_ptr and cyclic references23

Page 33: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

shared_ptr and cyclic referencesstruct SinkImpl : Sink, private noncopyable{ SinkImpl(SourcePtr source) : source_(source) {} void event_occurred() { ... }private: SourcePtr source_;};

void SourceImpl::set_observer(SinkPtr observer){ observer_ = observer; // Game Over: cyclic reference, both pointers leaked}

void SourceImpl::fire_event(){ if (observer_) observer_->event_occurred();}

SourcePtr source(new SourceImpl());SinkPtr sink(new SinkImpl(source));source->set_observer(sink);source->fire_event();

SinkImpl now has a strong reference to

Source

SourceImpl now has a strong reference

to Sink

24

Page 34: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Enter boost::weak_ptrstruct Source;typedef shared_ptr<Source> SourcePtr;

struct Sink{ virtual void event_occurred() = 0;};typedef shared_ptr<Sink> SinkPtr;

struct SourceImpl : Source{ void set_observer(SinkPtr observer);private:

weak_ptr<Sink> observer_;};

We still take a shared_ptr parameter

but store a weak_ptr

25

Page 35: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

struct SinkImpl{ SinkImpl(SourcePtr source) : source_(source) {} void event_occurred() { ... }private: SourcePtr source_;};

void SourceImpl::set_observer(SinkPtr observer){ observer_ = observer;}

void SourceImpl::fire_event(){ if (SinkPtr p = observer_.lock()) { p->event_occurred(); }}

SourcePtr source(new SourceImpl()); ...

Enter weak_ptr (continued)

lock() returns shared_ptr<Sink>

shared_ptr can be used inboolean expressions, handy in

conditional assignments like this

26

Page 36: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

struct SinkImpl : Sink, enable_shared_from_this<Sink>{ // SinkImpl(SourcePtr source) : source_(source) {}

void set_source(SourcePtr source) { source_ = source; source_->set_observer(shared_from_this()); } // ...};

boost::enable_shared_from_this

#include <boost/enable_shared_from_this.hpp>

27

Page 37: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

string you_can_do_this_as_well(){ char* raw = reinterpret_cast<char*>(malloc(1024)); shared_array<char> mem(raw, free); call_an_api_function(mem.get()); return raw;}// free(mem.get()) called at end of scope

But wait, there’s more!!!

// RAII is about resources, not just memory

void process_file(char const* file_path){ shared_ptr<FILE> file(fopen(file_path, “r”), fclose); read_data_from_file(file.get());}// fclose(file.get()) called at end of scope

you can pass a custom deleter

28

Page 38: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

If you’re still not convincedyou missed Boost’s smart

pointers you’rea C, not C++ programmer

Page 39: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Standard Library Bindersbind1stA helper template function that creates an adaptor to convert abinary function object into a unary function object by binding thefirst argument of the binary function to a specified value.

#include <boost/assign/std/vector.hpp> // operator+=()using namespace boost::assign;

typedef std::vector<int> Numbers;typedef Numbers::iterator iterator;Numbers nums;nums += 6, 9, 42, 54, 13; // yup, boost::assign rocks

iterator answer = find_if(nums.begin(),nums.end(), bind1st(equal_to<int>(), 42));

assert(answer != nums.end() && *answer == 42);

template <typename Operation, typename Type> binder1st<Operation> bind1st( Operation const& func, Type const& left);

template <typename Type>struct equal_to : binary_function<Type, Type, bool> { bool operator()( Type const& left, Type const& right) const;};

template <typename Type>struct equal_to : binary_function<Type, Type, bool> { bool operator()( Type const& left, Type const& right) const;};

template <typename InputIterator, typename Predicate>InputIterator find_if( InputIterator first, InputIterator last, Predicate pred); // Predicate: function object that defines// the condition to be satisfied by the element// being searched for.// A predicate takes single argument and returns// true or false.

29

Page 40: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Standard Library Bindersbind2ndA helper template function that creates an adaptor to convert abinary function object into a unary function object by binding thesecond argument of the binary function to a specified value.

// ...nums += 6, 9, 42, 54, 13; // yup, boost rocks

iterator it = find_if(nums.begin(),nums.end(), bind2nd(greater<int>(), 13));

assert(it != nums.end() && *it == 42);

template <typename Operation, typename Type> binder1st<Operation> bind2nd( Operation const& func, Type const& right);

30

Page 41: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.Bindboost::bindGeneralization of the standard functions std::bind1st and std::bind2nd.Supports arbitrary function objects, functions, function pointers, andmember function pointers, and is able to bind any argument to a specificvalue or route input arguments into arbitrary positions.

#include <boost/bind.hpp>nums += 6, 9, 42, 54, 13;

iterator fourty_two = find_if(nums.begin(),nums.end(), bind(equal_to<int>(), 42, _1));

iterator it = find_if(nums.begin(),nums.end(), bind(greater<int>(), _1, 13)); // note: _1, not _2

a “this ain’t C++”WTF moment:

_1 is a placeholder

emulating bind1st

emulating bind2nd

Warning,magic ahead

31

Page 42: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.BindWorks with functions and function pointers

int add(int x, int y) { return x + y; }int div(int x, int y) { return x / y; }

bind(add, _1, 7) // becomes unary function add(x, 7)// equivalent tobind2nd(ptr_fun(add), 7)// bind1st emulated as wellbind(add, 7, _1) // becomes unary function add(7, y)

bind(add, _1, 7)(3) // == add(3, 7) == 10

bind(add, 5, 7) // becomes nullary function add(5, 7)bind(add, 5, 7)() // == 12bind(add, 5, 7)(13, 42) // == 12 (extra args ignored)

// function pointersint (*pf)(int, int) = add;bind(pf, _2, _1)(2, 84) // pf(84, 2) == 42

btw, placeholders need not be in order

32

Page 43: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.Bindbind3rd, bind4th..., bind<N>th

int f(int x, int y, int z);int g(int a, int b, int c, int d);

bind(f, _1, _2, _3)(5, 6, 7) // f(5, 6, 7)bind(f, _1, 42, _2)(5, 13) // f(5, 42, 13)bind(f, _2, _1, 42)(5, 13) // f(13, 5, 42)bind(f, _1, _1, _1)(42, 43) // f(42, 42, 42)

bind(g, 1, _1, 3, 4)(2) // g(1, 2, 3, 4)

33

Page 44: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.BindWorks with function objects (functors)

struct Greeter{

void operator()(string const& name) const{

cout << “Hi “ << name << endl;}

};

Greeter g;bind<void>(g, _1)(“Boost”); // outputs “Hi Boost”bind<void>(ref(g), _1)(“Boost”); // dittobind<void>(Greeter(), _1)(“Boost”); // ditto

bind(less<int>(), _1, 42)

When the functor exposes a nested type named result_type (e.g. STL’s functors), the explicit return type can be omitted (but some compilers simply suck so it won’t work everywhere)

operator()’s return type must be explicitly specified

boost::ref in <boost/ref.hpp>avoids (expensive) copying of function objects

34

Page 45: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.BindWorks with pointers to members

bind(&T::f, args)

struct T{

void f(int val);};

T t;shared_ptr<T> p(new T);int v = 42;

bind(&T::f, &t, _1)(v) // (&t)->f(v)bind(&T::f, ref(t), _1)(v) // t.f(v)

bind(&T::f, t, _1)(v) // (internal-copy-of-t).f(v)bind(&T::f, p, _1)(v) // (internal-copy-of-p)->f(v)

// the last two produce self-contained function objects // (a.k.a. closures)

35

Page 46: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.BindOverloads operator! and relational operatorsstruct P // Participant – abbreviated to save space

{ explicit P(string const& name) : name_(name) {} P(P const& o) : name_(o.name_) {} P& operator=(P const& o) { return name_ = o.name_, *this; // one-liner to save space } string name_;};typedef vector<P> Participants;typedef Participants::iterator iterator;

Participants guys;guys += P("Stanimirov"), P("Nakov"), P("Nakov"), P("Penchev"); // ...

iterator i = adjacent_find(guys.begin(), guys.end(),!(bind(&P::name_, _1) != bind(&P::name_, _2)));

i = find_if(guys.begin(), guys.end(),bind(&P::name_, _1) == “Penchev”);

sort(guys.begin(), guys.end(), // Stanimirov, Penchev, Nakov, Nakovbind(&P::name_, _2) < bind(&P::name_, _1))

!(x != y) to demonstrate overloaded operator ! - equivalent to

bind(...name_, _1) == bind(...name_, _2)

36

Page 47: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.Lambda# RubyLanguage = Struct.new(:name, :desc)# names = %w{ Ruby C# C++ }# languages = names.collect { | n | Language.new(n, 'cool') }

languages.collect { | lang | print lang.name, ' ' }# outputs: Ruby C# C++

// C# 2langs.ForEach(delegate(Language lang)

{ Console.Write("{0} ", lang.Name); });

// C# 3langs.ForEach(lang => Console.Write("{0} ", lang.Name));

// C++ before Boost.Lambdatransform(langs.begin(), langs.end(), ostream_iterator<string>(cout, " "), bind(&L::name_, _1));

// C++ after Boost.Lambdafor_each(langs.begin(), lang.end(),

cout << bind(&L::name_, _1) << ' ');

#include <boost/bind.hpp>using namespace boost;#include <boost/bind.hpp>using namespace boost;

#include <boost/lambda/lambda.hpp>#include <boost/lambda/bind.hpp>using namespace boost;using namespace boost::lambda;

#include <boost/lambda/lambda.hpp>#include <boost/lambda/bind.hpp>using namespace boost;using namespace boost::lambda;

37

Warning,magic ahead

Page 48: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.Lambdastring name;for_each(

langs.begin(),lang.end(),

( var(name) = bind(&L::name_, _1), cout << var(name) << " is ", if_(var(name) == "C++") [cout << constant(“smart")] .else_ [cout << constant("dumb")], cout << constant(“\n"))

));

// Outputs:// Ruby is dumb// C# is dumb// C++ is smart

brackets are necessary, for_each accepts 3 arguments

Lambda expressions for control structures (flow control) Boost.Lambda supports: if-then[-else], while, do-while, for, switch; also try-catch, construction, cast, etc. expressions

delays evaluation of constants and variables

commas chain lambda expressions

Yes, thisis C++

38

Page 49: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.FunctionStores function pointers and function objects for subsequent invocation.

Anywhere where a function pointer would be used to defer a call or make a callback, Boost.Function can be used instead to allow the user greater flexibility in the implementation of the target.

Targets can be any 'compatible' function object (or function pointer), meaning that the arguments to the interface designated by Boost.Function can be converted to the arguments of the target function object

Preferred syntax Portable syntax

function<void()> f; function0<void> f;function<bool(int n)> f; function1<bool, int> f;

digit after “function” definesfunction arity (number of args)

39

Page 50: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.Functionfunction<bool(int)> f;

Free Functionsbool foo(int bar);f = foo; // f = &foo for MSVC 6 devsbool ret = f(42); // same as foo(42);

Functorsstruct T{

bool operator()(int bar);};f = T();bool ret = f(42); // same as T::operator()(42);

// if T is expensive to copyT t;f = ref(t); // boost::ref

40

Page 51: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.Functionfunction<bool(T*, int)> f;

Member functionsstruct T{

bool foo(int bar);};

f = &T::foo;

T t;

f(&t, 42);

41

Page 52: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.FunctionUsage

template <typename T>struct ThreadSafeContainer{

vector<T> items_;mutex mx_; // perhaps boost::mutex

};

// how to iterate its items in a thread-safe manner?

struct ThreadSafeContainer{

// 1) return a copyvector<T> return_copy(){

mutex::scoped_lock lock(mx_);return vector<T>(items_.begin(), items_.end());

}// expensive :(

};

42

Page 53: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.FunctionUsage

// how to iterate its items in a thread-safe manner?

struct ThreadSafeContainer{

// 2) expose the mutexmutex& get_mx(){

return mx_;}// error-prone, exposes implementation details

};

43

Page 54: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.FunctionUsage

// how to iterate its items in a thread-safe manner?

struct ThreadSafeContainer{ // 3) enumeration while locked void enumerate(function<void(T const& value)> enumerator) { mutex::scoped_lock lock(mx_); for_each(items_.begin(), items_.end(), enumerator); }};

ThreadSafeContainer<int> cont;// ...fill it in

// iterate in a thread-safe mannercont.enumerate(cout << _1 << constant("\n"));

44

Page 55: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.Signals

Managed signals and slots system

Signal: callback with multiple targets (multicast callback)a.k.a. publishera.k.a. event

Signals are connected to a set of slots (callback receivers)a.k.a. subscribersa.k.a. event targets

Makes Java’s listeners and .NET’s events laughable.

45

Page 56: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.SignalsPreferred syntax Portable syntax

signal<void()> event; signal0<void> event;signal<bool(int n)> sig; signal1<bool, int> sig;

event(); // fire event - no slots connected, nothing happens

// single slotvoid foo() { cout << “foo” << endl; }event.connect(&foo);event(); // outputs “foo”, new line

// multiple slots (foo and bar) connectedvoid bar() { cout << “bar” << endl; }event.connect(&foo);event.connect(&bar);event(); // outputs “foo”, new line, “bar”, new line

digit after “signal”declares arity

(number of args)

can have return value

46

Page 57: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.SignalsOrdering slotssignal<void()> sig;

void foo() { cout << “foo”; }void bar() { cout << “bar”; }void eol() { cout << endl; }

sig.connect(&eol);sig.connect(1, &bar);sig.connect(0, &foo);sig(); // outputs “foobar”, end-of-line

Passing values to slotssignal<void(int, int)> sig;

void sum(int x, int y) { cout << x << "+" << y << "=" << x + y; }void mul(int x, int y) { cout << x << "*" << y << "=" << x * y; }

sig.connect(&sum);sig.connect(&mul);sig(6, 7); // outputs: “6 + 7 = 13” and “6 * 7” = 42

slot order is defined by an optional 1st

parameter

non-grouped slots called last

47

Page 58: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.SignalsObtaining values from slotssignal<int(int, int)> calc;

int sum(int x, int y) { return x + y; }int mul(int x, int y) { return x * y; }

sig.connect(&sum);sig.connect(&mul);

int meaningless_result = sig(6, 7);

// ^^^ returns last called slot’s result

48

Page 59: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.SignalsObtaining values from slotstemplate <typename T> struct maximum{ typedef T result_type;

template <typename Iter> T operator()(Iter first, Iter last) const { // No slots to call -> return default-constructed value if (first == last) { return T(); }

T max_value = *first++; while (first != last) { if (max_value < *first) { max_value = *first; } ++first; } return max_value; }};

signal<int(int, int), maximum<int> > calc;int max = sig(6, 7); // max(13, 42) == 42

maximum is a combiner

combiner is a mechanism that can take the results of calling slots and coalesces them into a single result to be returned to the caller

allows for type deduction of signal’s return value

The input iterators passed to the combiner transform dereference operations into slot calls. This pull-based interface makes writing combiners a lot more easier.

49

Page 60: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.SignalsObtaining values from slotstemplate <typename C> struct aggregator{ typedef C result_type;

template <typename Iter> T operator()(Iter first, Iter last) const { return C(first, last); }};

signal<int(int, int), aggregator<vector<int> > > calc;vector<int> all_results(sig(6, 7));

50

Page 61: Excel in the Craft and prevent RSI with Stoyan Damov, founder and co-owner, CSGW Ltd.CSGW Ltd. stoyan@csgw.eu

Boost.ICE