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

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

Интервал:

Закладка:

Сделать

Our preference would be to employ a task-based design for this (see Item 35), but let's assume we'd like to set the priority of the thread doing the filtering. Item 35explains that that requires use of the thread's native handle, and that's accessible only through the std::threadAPI; the task-based API (i.e., futures) doesn't provide it. Our approach will therefore be based on threads, not tasks.

We could come up with code like this:

constexpr auto tenMillion = 10000000; // see Item 15

// for constexpr

bool doWork(std::function filter, // returns whether

int maxVal = tenMillion) // computation was

{ // performed; see

// Item 2 for

// std::function

std::vector goodVals; // values that

// satisfy filter

std::thread t([&filter, maxVal, &goodVals] // populate

{ // goodVals

for (auto i = 0; i <= maxVal; ++i)

{ if (filter(i)) goodVals.push_back(i); }

});

auto nh = t.native_handle(); // use t's native

… // handle to set

// t's priority

if ( conditionsAreSatisfied() ) {

t.join(); // let t finish

performComputation(goodVals) ;

return true; // computation was

} // performed

return false; // computation was

} // not performed

Before I explain why this code is problematic, I'll remark that tenMillion's initializing value can be made more readable in C++14 by taking advantage of C++14's ability to use an apostrophe as a digit separator:

constexpr auto tenMillion = 10 '000 '000; // C++14

I'll also remark that setting t's priority after it has started running is a bit like closing the proverbial barn door after the equally proverbial horse has bolted. A better design would be to start tin a suspended state (thus making it possible to adjust its priority before it does any computation), but I don't want to distract you with that code. If you're more distracted by the code's absence, turn to Item 39, because it shows how to start threads suspended.

But back to doWork. If conditionsAreSatisfied() returns true, all is well, but if it returns falseor throws an exception, the std::threadobject twill be joinable when its destructor is called at the end of doWork. That would cause program execution to be terminated.

You might wonder why the std::threaddestructor behaves this way. It's because the two other obvious options are arguably worse. They are:

An implicit join . In this case, a std::thread's destructor would wait for its underlying asynchronous thread of execution to complete. That sounds reasonable, but it could lead to performance anomalies that would be difficult to track down. For example, it would be counterintuitive that doWorkwould wait for its filter to be applied to all values if conditionsAreSatisfied() had already returned false.

An implicit detach . In this case, a std::thread's destructor would sever the connection between the std::threadobject and its underlying thread of execution. The underlying thread would continue to run. This sounds no less reasonable than the joinapproach, but the debugging problems it can lead to are worse. In doWork, for example, goodValsis a local variable that is captured by reference. It's also modified inside the lambda (via the call to push_back). Suppose, then, that while the lambda is running asynchronously, conditionsAreSatisfied() returns false. In that case, doWorkwould return, and its local variables (including goodVals) would be destroyed. Its stack frame would be popped, and execution of its thread would continue at doWork's call site.

Statements following that call site would, at some point, make additional function calls, and at least one such call would probably end up using some or all of the memory that had once been occupied by the doWorkstack frame. Let's call such a function f. While fwas running, the lambda that doWorkinitiated would still be running asynchronously. That lambda could call push_backon the stack memory that used to be goodValsbut that is now somewhere inside f's stack frame. Such a call would modify the memory that used to be goodVals, and that means that from f's perspective, the content of memory in its stack frame could spontaneously change! Imagine the fun you'd have debugging that .

The Standardization Committee decided that the consequences of destroying a joinable thread were sufficiently dire that they essentially banned it (by specifying that destruction of a joinable thread causes program termination).

This puts the onus on you to ensure that if you use a std::threadobject, it's made unjoinable on every path out of the scope in which it's defined. But covering every path can be complicated. It includes flowing off the end of the scope as well as jumping out via a return, continue, break, gotoor exception. That can be a lot of paths.

Any time you want to perform some action along every path out of a block, the normal approach is to put that action in the destructor of a local object. Such objects are known as RAII objects , and the classes they come from are known as RAII classes . ( RAII itself stands for “Resource Acquisition Is Initialization,” although the crux of the technique is destruction, not initialization). RAII classes are common in the Standard Library. Examples include the STL containers (each container's destructor destroys the container's contents and releases its memory), the standard smart pointers (Items 18–20explain that std::unique_ptr's destructor invokes its deleter on the object it points to, and the destructors in std::shared_ptrand std::weak_ptrdecrement reference counts), std::fstreamobjects (their destructors close the files they correspond to), and many more. And yet there is no standard RAII class for std::threadobjects, perhaps because the Standardization Committee, having rejected both joinand detachas default options, simply didn't know what such a class should do.

Fortunately, it's not difficult to write one yourself. For example, the following class allows callers to specify whether joinor detachshould be called when a ThreadRAIIobject (an RAII object for a std::thread) is destroyed:

class ThreadRAII {

public:

enum class DtorAction { join, detach }; // see Item 10 for

// enum class info

ThreadRAII(std::thread&& t, DtorAction a) // in dtor, take

: action(a), t(std::move(t)) {} // action a on t

~ThreadRAII()

{ // see below for

if (t.joinable()) { // joinability test

if (action == DtorAction::join) {

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

Интервал:

Закладка:

Сделать

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

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


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

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

x