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++», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

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

Интервал:

Закладка:

Сделать

auto func =

std::bind( // C++11 emulation

[]( std::vector&data) mutable// of init capture

{ /* uses of data */ }, // for mutable lambda

std::move(data)

);

Because a bind object stores copies of all the arguments passed to std::bind, the bind object in our example contains a copy of the closure produced by the lambda that is its first argument. The lifetime of the closure is therefore the same as the lifetime of the bind object. That's important, because it means that as long as the closure exists, the bind object containing the pseudo-move-captured object exists, too.

If this is your first exposure to std::bind, you may need to consult your favorite C++11 reference before all the details of the foregoing discussion fall into place. Even if that's the case, these fundamental points should be clear:

• It's not possible to move-construct an object into a C++11 closure, but it is possible to move-construct an object into a C++11 bind object.

• Emulating move-capture in C++11 consists of move-constructing an object into a bind object, then passing the move-constructed object to the lambda by reference.

• Because the lifetime of the bind object is the same as that of the closure, it's possible to treat objects in the bind object as if they were in the closure.

As a second example of using std::bindto emulate move capture, here's the C++14 code we saw earlier to create a std::unique_ptrin a closure:

auto func = [ pw = std::make_unique()] // as before,

{ return pw->isValidated() // create pw

&& pw->isArchived(); }; // in closure

And here's the C++11 emulation:

auto func = std::bind(

[]( const std::unique_ptr& pw)

{ return pw->isValidated()

&& pw->isArchived(); },

std::make_unique()

);

It's ironic that I'm showing how to use std::bindto work around limitations in C++11 lambdas, because in Item 34, I advocate the use of lambdas over std::bind. However, that Item explains that there are some cases in C++11 where std::bindcan be useful, and this is one of them. (In C++14, features such as init capture and autoparameters eliminate those cases.)

Things to Remember

• Use C++14's init capture to move objects into closures.

• In C++11, emulate init capture via hand-written classes or std::bind.

Item 33: Use decltypeon auto&&parameters to std::forwardthem.

One of the most exciting features of C++14 is generic lambdas — lambdas that use autoin their parameter specifications. The implementation of this feature is straightforward: operator()in the lambda's closure class is a template. Given this lambda, for example,

auto f = []( autox){ return func(normalize(x)); };

the closure class's function call operator looks like this:

class SomeCompilerGeneratedClassName {

public:

template // see Item 3 for

auto operator()( Tx) const // auto return type

{ return func(normalize(x)); }

… // other closure class

}; // functionality

In this example, the only thing the lambda does with its parameter xis forward it to normalize. If normalizetreats lvalues differently from rvalues, this lambda isn't written properly, because it always passes an lvalue (the parameter x) to normalize, even if the argument that was passed to the lambda was an rvalue.

The correct way to write the lambda is to have it perfect-forward xto normalize. Doing that requires two changes to the code. First, xhas to become a universal reference (see Item 24), and second, it has to be passed to normalizevia std::forward(see Item 25). In concept, these are trivial modifications:

auto f = [](auto &&x)

{ return func(normalize( std::forward (x ))); };

Between concept and realization, however, is the question of what type to pass to std::forward, i.e., to determine what should go where I've written ???above.

Normally, when you employ perfect forwarding, you're in a template function taking a type parameter T, so you just write std::forward. In the generic lambda, though, there's no type parameter Tavailable to you. There is a Tin the templatized operator()inside the closure class generated by the lambda, but it's not possible to refer to it from the lambda, so it does you no good.

Item 28explains that if an lvalue argument is passed to a universal reference parameter, the type of that parameter becomes an lvalue reference. If an rvalue is passed, the parameter becomes an rvalue reference. This means that in our lambda, we can determine whether the argument passed was an lvalue or an rvalue by inspecting the type of the parameter x. decltypegives us a way to do that (see Item 3). If an lvalue was passed in, decltype(x)will produce a type that's an lvalue reference. If an rvalue was passed, decltype(x)will produce an rvalue reference type.

Item 28also explains that when calling std::forward, convention dictates that the type argument be an lvalue reference to indicate an lvalue and a non-reference to indicate an rvalue. In our lambda, if xis bound to an lvalue, decltype(x)will yield an lvalue reference. That conforms to convention. However, if x is bound to an rvalue, decltype(x)will yield an rvalue reference instead of the customary non- reference.

But look at the sample C++14 implementation for std::forwardfrom Item 28:

template // in namespace

T&& forward(remove_reference_t& param) // std

{

return static_cast(param);

}

If client code wants to perfect-forward an rvalue of type Widget, it normally instantiates std::forwardwith the type Widget(i.e, a non-reference type), and the std::forwardtemplate yields this function:

Widget&& forward( Widget& param) // instantiation of

{ // std::forward when

return static_cast< Widget&&>(param); // T is Widget

}

But consider what would happen if the client code wanted to perfect-forward the same rvalue of type Widget, but instead of following the convention of specifying Tto be a non-reference type, it specified it to be an rvalue reference. That is, consider what would happen if Twere specified to be Widget&&. After initial instantiation of std::forwardand application of std::remove_reference_t, but before reference collapsing (once again, see Item 28), std::forwardwould look like this:

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

Интервал:

Закладка:

Сделать

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

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


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

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

x