C++.Coding.Standards.1918.Rules.Guidelines [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

C++.Coding.Standards.1918.Rules.Guidelines [Electronic resources] - نسخه متنی

Herb Sutter, Andrei Alexandrescu

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید


Examples


Here are two examples adapted from [Meyers01]:

Example 1: Transforming a

deque.
After working through several incorrect iterations that ran afoul of iterator invalidation issues (e.g., see Item 83), we finally come up with the following correct handwritten loop for adding

41 to every element of

data , an array of

double s, and placing the result at the beginning of

d , a

deque<double> :

deque<double>::iterator current = d.begin();
for( size_t i = 0; i < max; ++i ) {
current = d.insert( current, data[i] + 41 );

// be careful to keep current valid…
++current;

// … then increment it when it's safe
}

An algorithm call would have bypassed the correctness pitfalls straight away:

transform( data, data + max,

// copy elements from data
inserter(d, d.begin()),

// to the front of d

bind2nd(plus<double>(), 41) );

// adding 41 to each

Granted,

bind2nd and

plus are awkward. Frankly, nobody really uses them much, and that's just as well because they hurt readability (see 6).

But lambda functions, which generate the function object for us, let us write simply:

transform( data, data + max, inserter( d, d.begin() ),

_1 + 41 );

Example 2: Find the first element between

x

and

y.
Consider this naked loop that searches a

vector<int> v for the first value between

x and

y , by calculating an iterator that points to the found element or to

v.end() :

for( vector<int>::iterator i = v.begin(); i != v.end(); ++i )
if( *i > x && *i < y ) break;

An algorithm call is problematic. Absent lambdas, the two options are to write a custom function object or to use the standard binders. Alas, with the binders option we can't use the standard binders alone but need to use the nonstandard (although widely-available)

compose2 adapter, and even at that the code is just impenetrable, and nobody would ever really write it:

vector<int>::iterator i = find_if( v.begin(), v.end(),

compose2( logical_and<bool>(),

bind2nd(greater<int>(), x),

bind2nd(less<int>(), y) ) );

The other option, namely writing a custom function object, is viable. It looks good at the call point, and its main drawback is that it requires writing a

BetweenValues function object that moves the body's logic visually away from the call point:

template<typename T>
class BetweenValues : public unary_function<T, bool> {
public:
BetweenValues( const T& low, const T& high ) : low_(low), high_(high) {}
bool operator()( const T& val ) const {return

val > low_ && val < high_ ; }
private:

// far away from the point of use
T low_, high_;
};
vector<int>::iterator i = find_if( v.begin(), v.end(),

BetweenValues<int>(x, y) );

Lambda functions, which generate the function object for us, let us write simply:

vector<int>::iterator i = find_if( v.begin(), v.end(),

_1 > x && _1 < y );


/ 521