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

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

Интервал:

Закладка:

Сделать

t.join();

} else {

t.detach();

}

}

}

std::thread& get() { return t; } // see below

private:

DtorAction action;

std::thread t;

};

I hope this code is largely self-explanatory, but the following points may be helpful:

• The constructor accepts only std::threadrvalues, because we want to move the passed-in std::threadinto the ThreadRAIIobject. (Recall that std::threadobjects aren't copyable.)

• The parameter order in the constructor is designed to be intuitive to callers (specifying the std::threadfirst and the destructor action second makes more sense than vice versa), but the member initialization list is designed to match the order of the data members' declarations. That order puts the std::threadobject last. In this class, the order makes no difference, but in general, it's possible for the initialization of one data member to depend on another, and because std::threadobjects may start running a function immediately after they are initialized, it's a good habit to declare them last in a class. That guarantees that at the time they are constructed, all the data members that precede them have already been initialized and can therefore be safely accessed by the asynchronously running thread that corresponds to the std::threaddata member.

ThreadRAIIoffers a getfunction to provide access to the underlying std::threadobject. This is analogous to the getfunctions offered by the standard smart pointer classes that give access to their underlying raw pointers. Providing getavoids the need for ThreadRAIIto replicate the full std::threadinterface, and it also means that ThreadRAIIobjects can be used in contexts where std::threadobjects are required.

• Before the ThreadRAIIdestructor invokes a member function on the std::threadobject t, it checks to make sure that tis joinable. This is necessary, because invoking joinor detachon an unjoinable thread yields undefined behavior. It's possible that a client constructed a std::thread, created a ThreadRAIIobject from it, used getto acquire access to t, and then did a move from tor called joinor detachon it. Each of those actions would render tunjoinable.

If you're worried that in this code,

if ( t.joinable()) {

if (action == DtorAction::join) {

t.join();

} else {

t.detach();

}

}

a race exists, because between execution of t.joinable()and invocation of joinor detach, another thread could render tunjoinable, your intuition is commendable, but your fears are unfounded. A std::threadobject can change state from joinable to unjoinable only through a member function call, e.g., join, detach, or a move operation. At the time a ThreadRAIIobject's destructor is invoked, no other thread should be making member function calls on that object. If there are simultaneous calls, there is certainly a race, but it isn't inside the destructor, it's in the client code that is trying to invoke two member functions (the destructor and something else) on one object at the same time. In general, simultaneous member function calls on a single object are safe only if all are to constmember functions (see Item 16).

Employing ThreadRAIIin our doWorkexample would look like this:

bool doWork(std::function filter, // as before

int maxVal = tenMillion) {

std::vector goodVals; // as before

ThreadRAII t( // use RAII object

std::thread([&filter, maxVal, &goodVals] {

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

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

}),

ThreadRAII::DtorAction::join// RAII action

);

auto nh = t.get().native_handle();

if ( conditionsAreSatisfied() ) {

t. get().join();

performComputation(goodVals) ;

return true;

}

return false;

}

In this case, we've chosen to do a joinon the asynchronously running thread in the ThreadRAIIdestructor, because, as we saw earlier, doing a detachcould lead to some truly nightmarish debugging. We also saw earlier that doing a joincould lead to performance anomalies (that, to be frank, could also be unpleasant to debug), but given a choice between undefined behavior (which detach would get us), program termination (which use of a raw std::threadwould yield), or performance anomalies, performance anomalies seems like the best of a bad lot.

Alas, Item 39demonstrates that using ThreadRAIIto perform a joinon std::threaddestruction can sometimes lead not just to a performance anomaly, but to a hung program. The “proper” solution to these kinds of problems would be to communicate to the asynchronously running lambda that we no longer need its work and that it should return early, but there's no support in C++11 for interruptible threads . They can be implemented by hand, but that's a topic beyond the scope of this book. [17] You'll find a nice treatment in Anthony Williams' C++ Concurrency in Action (Manning Publications, 2012), section 9.2.

Item 17explains that because ThreadRAIIdeclares a destructor, there will be no compiler-generated move operations, but there is no reason ThreadRAIIobjects shouldn't be movable. If compilers were to generate these functions, the functions would do the right thing, so explicitly requesting their creation isappropriate:

class ThreadRAII {

public:

enum class DtorAction { join, detach }; // as before

ThreadRAII(std::thread&& t, DtorAction a) // as before

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

~ThreadRAII() {

… // as before

}

ThreadRAII(ThreadRAII&&) = default; // support

ThreadRAII& operator=(ThreadRAII&&) = default;// moving

std::thread& get() { return t; } // as before

private: // as before

DtorAction action;

std::thread t;

};

Things to Remember

• Make std::threads unjoinable on all paths.

join-on-destruction can lead to difficult-to-debug performance anomalies.

detach-on-destruction can lead to difficult-to-debug undefined behavior.

• Declare std::threadobjects last in lists of data members.

Item 38: Be aware of varying thread handle destructor behavior.

Item 37explains that a joinable std::threadcorresponds to an underlying system thread of execution. A future for a non-deferred task (see Item 36) has a similar relationship to a system thread. As such, both std::threadobjects and future objects can be thought of as handles to system threads.

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

Интервал:

Закладка:

Сделать

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

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


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

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

x