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

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

Интервал:

Закладка:

Сделать

using FilterContainer = // as before

std::vector>;

FilterContainer filters; // as before

void doSomeWork() {

auto pw = // create Widget; see

std::make_unique(); // Item 21 for

// std::make_unique

pw->addFilter(); // add filter that uses

// Widget::divisor

} // destroy Widget; filters

// now holds dangling pointer!

When a call is made to doSomeWork, a filter is created that depends on the Widgetobject produced by std::make_unique, i.e., a filter that contains a copy of a pointer to that Widget— the Widget's thispointer. This filter is added to filters, but when doSomeWorkfinishes, the Widgetis destroyed by the std::unique_ptrmanaging its lifetime (see Item 18). From that point on, filterscontains an entry with a dangling pointer.

This particular problem can be solved by making a local copy of the data member you want to capture and then capturing the copy:

void Widget::addFilter() const {

auto divisorCopy = divisor; // copy data member

filters.emplace_back(

[divisorCopy](int value) // capture the copy

{ return value % divisorCopy== 0; } // use the copy

);

}

To be honest, if you take this approach, default by-value capture will work, too,

void Widget::addFilter() const {

auto divisorCopy = divisor; // copy data member

filters.emplace_back(

[=](int value) // capture the copy

{ return value % divisorCopy== 0; } // use the copy

);

}

but why tempt fate? A default capture mode is what made it possible to accidentally capture thiswhen you thought you were capturing divisorin the first place.

In C++14, a better way to capture a data member is to use generalized lambda capture (see Item 32):

void Widget::addFilter() const {

filters.emplace_back( // C++14:

[divisor = divisor](int value) // copy divisor to closure

{ return value % divisor== 0; } // use the copy

);

}

There's no such thing as a default capture mode for a generalized lambda capture, however, so even in C++14, the advice of this Item — to avoid default capture modes — stands.

An additional drawback to default by-value captures is that they can suggest that the corresponding closures are self-contained and insulated from changes to data outside the closures. In general, that's not true, because lambdas may be dependent not just on local variables and parameters (which may be captured), but also on objects with static storage duration . Such objects are defined at global or namespace scope or are declared staticinside classes, functions, or files. These objects can be used inside lambdas, but they can't be captured. Yet specification of a default by-value capture mode can lend the impression that they are. Consider this revised version of the addDivisorFilterfunction we saw earlier:

void addDivisorFilter() {

staticauto calc1 = computeSomeValue1(); // now static

staticauto calc2 = computeSomeValue2(); // now static

staticauto divisor= // now static

computeDivisor(calc1, calc2);

filters.emplace_back(

[=](int value) // captures nothing!

{ return value % divisor == 0; } // refers to above static

);

++divisor; // modify divisor

}

A casual reader of this code could be forgiven for seeing “ [=]” and thinking, “Okay, the lambda makes a copy of all the objects it uses and is therefore self-contained.” But it's not self-contained. This lambda doesn't use any non-static local variables, so nothing is captured. Rather, the code for the lambda refers to the staticvariable divisor. When, at the end of each invocation of addDivisorFilter, divisoris incremented, any lambdas that have been added to filtersvia this function will exhibit new behavior (corresponding to the new value of divisor). Practically speaking, this lambda captures divisorby reference, a direct contradiction to what the default by-value capture clause seems to imply. If you stay away from default by-value capture clauses, you eliminate the risk of your code being misread in this way.

Things to Remember

• Default by-reference capture can lead to dangling references.

• Default by-value capture is susceptible to dangling pointers (especially this), and it misleadingly suggests that lambdas are self-contained.

Item 32: Use init capture to move objects into closures.

Sometimes neither by-value capture nor by-reference capture is what you want. If you have a move-only object (e.g., a std::unique_ptror a std::future) that you want to get into a closure, C++11 offers no way to do it. If you have an object that's expensive to copy but cheap to move (e.g., most containers in the Standard Library), and you'd like to get that object into a closure, you'd much rather move it than copy it. Again, however, C++11 gives you no way to accomplish that.

But that's C++11. C++14 is a different story. It offers direct support for moving objects into closures. If your compilers are C++14-compliant, rejoice and read on. If you're still working with C++11 compilers, you should rejoice and read on, too, because there are ways to approximate move capture in C++11.

The absence of move capture was recognized as a shortcoming even as C++11 was adopted. The straightforward remedy would have been to add it in C++14, but the Standardization Committee chose a different path. They introduced a new capture mechanism that's so flexible, capture-by-move is only one of the tricks it can perform. The new capability is called init capture . It can do virtually everything the C++11 capture forms can do, plus more. The one thing you can't express with an init capture is a default capture mode, but Item 31explains that you should stay away from those, anyway. (For situations covered by C++11 captures, init capture's syntax is a bit wordier, so in cases where a C++11 capture gets the job done, it's perfectly reasonable to use it.)

Using an init capture makes it possible for you to specify

1. the name of a data memberin the closure class generated from the lambda and

2. an expressioninitializing that data member.

Here's how you can use init capture to move a std::unique_ptrinto a closure:

class Widget { // some useful type

public:

bool isValidated() const;

bool isProcessed() const;

bool isArchived() const;

private:

};

auto pw = std::make_unique(); // create Widget; see

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

Интервал:

Закладка:

Сделать

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

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


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

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

x