Scott Meyers - Effective Modern C++

Здесь есть возможность читать онлайн «Scott Meyers - Effective Modern C++» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Город: Sebastopol, Год выпуска: 2014, ISBN: 2014, Издательство: O’Reilly, Жанр: Программирование, на английском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

Effective Modern C++: краткое содержание, описание и аннотация

Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Effective Modern C++»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.

Coming to grips with C++11 and C++14 is more than a matter of familiarizing yourself with the features they introduce (e.g., auto type declarations, move semantics, lambda expressions, and concurrency support). The challenge is learning to use those features
— so that your software is correct, efficient, maintainable, and portable. That's where this practical book comes in. It describes how to write truly great software using C++11 and C++14 — i.e., using
C++.
Topics include:
■ The pros and cons of braced initialization,
specifications, perfect forwarding, and smart pointer make functions
■ The relationships among
,
, rvalue references, and universal references
■ Techniques for writing clear, correct,
lambda expressions
■ How
differs from
, how each should be used, and how they relate to C++'s concurrency API
■ How best practices in “old” C++ programming (i.e., C++98) require revision for software development in modern C++
Effective Modern C++ For more than 20 years,
'
books (
,
, and
) have set the bar for C++ programming guidance. His clear, engaging explanations of complex technical material have earned him a worldwide following, keeping him in demand as a trainer, consultant, and conference presenter. He has a Ph.D. in Computer Science from Brown University.
“After I learned the C++ basics, I then learned how to use C++ in production code from Meyers' series of Effective C++ books. Effective Modern C++ is the most important how-to book for advice on key guidelines, styles, and idioms to use modern C++ effectively and well. Don't own it yet? Buy this one. Now.”
Herb Sutter
Chair of ISO C++ Standards Committee and C++ Software Architect at Microsoft

Effective Modern C++ — читать онлайн бесплатно полную книгу (весь текст) целиком

Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Effective Modern C++», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

But, as I said, the code isn't quite right. In the lambda, it's clear that the expression “ steady_clock::now() + 1h” is an argument to setAlarm. It will be evaluated when setAlarmis called. That makes sense: we want the alarm to go off an hour after invoking setAlarm. In the std::bindcall, however, “ steady_clock::now() + 1h” is passed as an argument to std::bind, not to setAlarm. That means that the expression will be evaluated when std::bindis called, and the time resulting from that expression will be stored inside the resulting bind object. As a consequence, the alarm will be set to go off an hour after the call to std::bind , not an hour after the call to setAlarm!

Fixing the problem requires telling std::bindto defer evaluation of the expression until setAlarmis called, and the way to do that is to nest a second call to std::bindinside the first one:

auto setSoundB =

std::bind(setAlarm,

std::bind(std::plus<>(), steady_clock::now(), 1h),

_1,

30s);

If you're familiar with the std::plustemplate from C++98, you may be surprised to see that in this code, no type is specified between the angle brackets, i.e., the code contains “ std::plus<>”, not " std::plus". In C++14, the template type argument for the standard operator templates can generally be omitted, so there's no need to provide it here. C++11 offers no such feature, so the C++11 std::bindequivalent to the lambda is:

using namespace std::chrono; // as above

using namespace std::placeholders;

auto setSoundB =

std::bind(setAlarm,

std::bind(std::plus< steady_clock::time_point>(),

steady_clock::now(),

hours(1)),

_1,

seconds(30));

If, at this point, the lambda's not looking a lot more attractive, you should probably have your eyesight checked.

When setAlarmis overloaded, a new issue arises. Suppose there's an overload taking a fourth parameter specifying the alarm volume:

enum class Volume { Normal, Loud, LoudPlusPlus };

void setAlarm(Time t, Sound s, Duration d, Volume v);

The lambda continues to work as before, because overload resolution chooses the three-argument version of setAlarm:

auto setSoundL = // same as before

[](Sound s) {

using namespace std::chrono;

setAlarm(steady_clock::now() + 1h, // fine, calls

s, // 3-arg version

30s); // of setAlarm

};

The std::bindcall, on the other hand, now fails to compile:

auto setSoundB = // error! which

std::bind(setAlarm, // setAlarm?

std::bind(std::plus<>(),

steady_clock::now(),

1h),

_1,

30s);

The problem is that compilers have no way to determine which of the two setAlarmfunctions they should pass to std::bind. All they have is a function name, and the name alone is ambiguous.

To get the std::bindcall to compile, setAlarmmust be cast to the proper function pointer type:

using SetAlarm3ParamType = void(*)(Time t, Sound s, Duration d);

auto setSoundB = // now

std::bind( static_cast(setAlarm ), // okay

std::bind(std::plus<>(),

steady_clock::now(),

1h),

_1,

30s);

But this brings up another difference between lambdas and std::bind. Inside the function call operator for setSoundL(i.e., the function call operator of the lambda's closure class), the call to setAlarmis a normal function invocation that can be inlined by compilers in the usual fashion:

setSound L(Sound::Siren); // body of setAlarm may

// well be inlined here

The call to std::bind, however, passes a function pointer to setAlarm, and that means that inside the function call operator for setSoundB(i.e., the function call operator for the bind object), the call to setAlarmtakes place through a function pointer. Compilers are less likely to inline function calls through function pointers, and that means that calls to setAlarmthrough setSoundBare less likely to be fully inlined than those through setSoundL:

setSound B(Sound::Siren); // body of setAlarm is less

// likely to be inlined here

It's thus possible that using lambdas generates faster code than using std::bind.

The setAlarmexample involves only a simple function call. If you want to do anything more complicated, the scales tip even further in favor of lambdas. For example, consider this C++14 lambda, which returns whether its argument is between a minimum value ( lowVal) and a maximum value ( highVal), where lowValand highValare local variables:

auto betweenL =

[lowVal, highVal]

(const auto& val) // C++14

{ return lowVal <= val && val <= highVal; };

std::bindcan express the same thing, but the construct is an example of job security through code obscurity:

using namespace std::placeholders; // as above

auto betweenB =

std::bind(std::logical_and<>(), // C++14

std::bind(std::less_equal<>(), lowVal, _1),

std::bind(std::less_equal<>(), _1, highVal));

In C++11, we'd have to specify the types we wanted to compare, and the std::bindcall would then look like this:

auto betweenB = // C++11 version

std::bind(std::logical_and< bool>(),

std::bind(std::less_equal< int>(), lowVal, _1),

std::bind(std::less_equal< int>(), _1, highVal));

Of course, in C++11, the lambda couldn't take an autoparameter, so it'd have to commit to a type, too:

auto betweenL = // C++11 version

[lowVal, highVal]

( int val)

{ return lowVal <= val && val <= highVal; };

Either way, I hope we can agree that the lambda version is not just shorter, but also more comprehensible and maintainable.

Earlier, I remarked that for those with little std::bindexperience, its placeholders (e.g., _1, _2, etc.) are essentially magic. But it's not just the behavior of the placeholders that's opaque. Suppose we have a function to create compressed copies of Widgets,

enum class CompLevel { Low, Normal, High }; // compression

// level

Widget compress(const Widget& w, // make compressed

CompLevel lev); // copy of w

and we want to create a function object that allows us to specify how much a particular Widget wshould be compressed. This use of std::bindwill create such an object:

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Похожие книги на «Effective Modern C++»

Представляем Вашему вниманию похожие книги на «Effective Modern C++» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.


Отзывы о книге «Effective Modern C++»

Обсуждение, отзывы о книге «Effective Modern C++» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.

x