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

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

Интервал:

Закладка:

Сделать

// Item 21 for info on

// std::make_unique

… // configure *pw

auto func = [ pw = std::move(pw)] // init data mbr

{ return pw->isValidated() // in closure w/

&& pw->isArchived(); }; // std::move(pw)

The highlighted text comprises the init capture. To the left of the “ =” is the name of the data member in the closure class you're specifying, and to the right is the initializing expression. Interestingly, the scope on the left of the “ =” is different from the scope on the right. The scope on the left is that of the closure class. The scope on the right is the same as where the lambda is being defined. In the example above, the name pwon the left of the “ =” refers to a data member in the closure class, while the name pwon the right refers to the object declared above the lambda, i.e., the variable initialized by the call to std::make_unique. So “ pw = std::move(pw)” means “create a data member pwin the closure, and initialize that data member with the result of applying std::moveto the local variable pw.”

As usual, code in the body of the lambda is in the scope of the closure class, so uses of pwthere refer to the closure class data member.

The comment “configure *pw” in this example indicates that after the Widgetis created by std::make_uniqueand before the std::unique_ptrto that Widgetis captured by the lambda, the Widgetis modified in some way. If no such configuration is necessary, i.e., if the Widgetcreated by std::make_uniqueis in a state suitable to be captured by the lambda, the local variable pwis unnecessary, because the closure class's data member can be directly initialized by std::make_unique:

auto func = [ pw = std::make_unique()] // init data mbr

{ return pw->isValidated() // in closure w/

&& pw->isArchived(); }; // result of call

// to make_unique

This should make clear that the C++14 notion of “capture” is considerably generalized from C++11, because in C++11, it's not possible to capture the result of an expression. As a result, another name for init capture is generalized lambda capture .

But what if one or more of the compilers you use lacks support for C++14's init capture? How can you accomplish move capture in a language lacking support for move capture?

Remember that a lambda expression is simply a way to cause a class to be generated and an object of that type to be created. There is nothing you can do with a lambda that you can't do by hand. The example C++14 code we just saw, for example, can be written in C++11 like this:

class IsValAndArch { // "is validated

public: // and archived"

using DataType = std::unique_ptr;

explicit IsValAndArch(DataType&& ptr) // Item 25 explains

: pw(std::move(ptr)) {} // use of std::move

bool operator()() const

{ return pw->isValidated() && pw->isArchived(); }

private:

DataType pw;

};

auto func = IsValAndArch(std::make_unique());

That's more work than writing the lambda, but it doesn't change the fact that if you want a class in C++11 that supports move-initialization of its data members, the only thing between you and your desire is a bit of time with your keyboard.

If you want to stick with lambdas (and given their convenience, you probably do), move capture can be emulated in C++11 by

1. moving the object to be captured into a function object produced by std::bind and

2. giving the lambda a reference to the “captured” object.

If you're familiar with std::bind, the code is pretty straightforward. If you're not familiar with std::bind, the code takes a little getting used to, but it's worth the trouble.

Suppose you'd like to create a local std::vector, put an appropriate set of values into it, then move it into a closure. In C++14, this is easy:

std::vector data; // object to be moved

// into closure

… // populate data

auto func = [data = std::move(data)] // C++14 init capture

{ /* uses of data */ };

I've highlighted key parts of this code: the type of object you want to move ( std::vector), the name of that object ( data), and the initializing expression for the init capture ( std::move(data)). The C++11 equivalent is as follows, where I've highlighted the same key things:

std::vector data; // as above

… // as above

auto func =

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

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

{ /* uses of data */ },

std::move(data)

);

Like lambda expressions, std::bindproduces function objects. I call function objects returned by std::bind bind objects . The first argument to std::bindis a callable object. Subsequent arguments represent values to be passed to that object.

A bind object contains copies of all the arguments passed to std::bind. For each lvalue argument, the corresponding object in the bind object is copy constructed. For each rvalue, it's move constructed. In this example, the second argument is an rvalue (the result of std::move— see Item 23), so datais move constructed into the bind object. This move construction is the crux of move capture emulation, because moving an rvalue into a bind object is how we work around the inability to move an rvalue into a C++11 closure.

When a bind object is “called” (i.e., its function call operator is invoked) the arguments it stores are passed to the callable object originally passed to std::bind. In this example, that means that when func(the bind object) is called, the move-constructed copy of data inside funcis passed as an argument to the lambda that was passed to std::bind.

This lambda is the same as the lambda we'd use in C++14, except a parameter, data, has been added to correspond to our pseudo-move-captured object. This parameter is an lvalue reference to the copy of datain the bind object. (It's not an rvalue reference, because although the expression used to initialize the copy of data(“ std::move(data)”) is an rvalue, the copy of dataitself is an lvalue.) Uses of datainside the lambda will thus operate on the move-constructed copy of data inside the bind object.

By default, the operator()member function inside the closure class generated from a lambda is const. That has the effect of rendering all data members in the closure constwithin the body of the lambda. The move-constructed copy of datainside the bind object is not const, however, so to prevent that copy of datafrom being modified inside the lambda, the lambda's parameter is declared reference-to- const. If the lambda were declared mutable, operator()in its closure class would not be declared const, and it would be appropriate to omit constin the lambda's parameter declaration:

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

Интервал:

Закладка:

Сделать

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

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


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

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

x