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

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

Интервал:

Закладка:

Сделать

std::shared_ptr p;

};

std::string getWidgetName(); // factory function

Widget w;

auto n = getWidgetName(); // n is local variable

w.setName(n); // moves n into w!

… // n's value now unknown

Here, the local variable nis passed to w.setName, which the caller can be forgiven for assuming is a read-only operation on n. But because setNameinternally uses std::moveto unconditionally cast its reference parameter to an rvalue, n's value will be moved into w.name, and nwill come back from the call to setNamewith an unspecified value. That's the kind of behavior that can drive callers to despair — possibly to violence.

You might argue that setNameshouldn't have declared its parameter to be a universal reference. Such references can't be const(see Item 24), yet setNamesurely shouldn't modify its parameter. You might point out that if setNamehad simply been overloaded for constlvalues and for rvalues, the whole problem could have been avoided. Like this:

class Widget {

public:

void setName( const std::string&newName) // set from

{ name = newName; } // const lvalue

void setName(std::string&& newName) // set from

{ name = std::move(newName); } // rvalue

};

That would certainly work in this case, but there are drawbacks. First, it's more source code to write and maintain (two functions instead of a single template). Second, it can be less efficient. For example, consider this use of setName:

w.setName("Adela Novak");

With the version of setNametaking a universal reference, the string literal "Adela Novak"would be passed to setName, where it would be conveyed to the assignment operator for the std::stringinside w. w's namedata member would thus be assigned directly from the string literal; no temporary std::stringobjects would arise. With the overloaded versions of setName, however, a temporary std::stringobject would be created for setName's parameter to bind to, and this temporary std::stringwould then be moved into w's data member. A call to setNamewould thus entail execution of one std::stringconstructor (to create the temporary), one std::stringmove assignment operator (to move newNameinto w.name), and one std::stringdestructor (to destroy the temporary). That's almost certainly a more expensive execution sequence than invoking only the std::stringassignment operator taking a const char*pointer. The additional cost is likely to vary from implementation to implementation, and whether that cost is worth worrying about will vary from application to application and library to library, but the fact is that replacing a template taking a universal reference with a pair of functions overloaded on lvalue references and rvalue references is likely to incur a runtime cost in some cases. If we generalize the example such that Widget's data member may be of an arbitrary type (rather than knowing that it's std::string), the performance gap can widen considerably, because not all types are as cheap to move as std::string(see Item 29).

The most serious problem with overloading on lvalues and rvalues, however, isn't the volume or idiomaticity of the source code, nor is it the code's runtime performance. It's the poor scalability of the design. Widget::setNametakes only one parameter, so only two overloads are necessary, but for functions taking more parameters, each of which could be an lvalue or an rvalue, the number of overloads grows geometrically: n parameters necessitates 2 overloads. And that's not the worst of it. Some functions — function templates, actually — take an unlimited number of parameters, each of which could be an lvalue or rvalue. The poster children for such functions are std::make_shared, and, as of C++14, std::make_unique(see Item 21). Check out the declarations of their most commonly used overloads:

template // from C++11

shared_ptr make_shared( Args&&...args); // Standard

template // from C++14

unique_ptr make_unique( Args&&...args); // Standard

For functions like these, overloading on lvalues and rvalues is not an option: universal references are the only way to go. And inside such functions, I assure you, std::forwardis applied to the universal reference parameters when they're passed to other functions. Which is exactly what you should do.

Well, usually. Eventually. But not necessarily initially. In some cases, you'll want to use the object bound to an rvalue reference or a universal reference more than once in a single function, and you'll want to make sure that it's not moved from until you're otherwise done with it. In that case, you'll want to apply std::move(for rvalue references) or std::forward(for universal references) to only the final use of the reference. For example:

template // text is

void setSignText(T&& text) // univ. reference

{

sign.setText( text); // use text, but

// don't modify it

auto now = // get current time

std::chrono::system_clock::now();

signHistory.add(now,

std::forward( text)); // conditionally cast

} // text to rvalue

Here, we want to make sure that text's value doesn't get changed by sign.setText, because we want to use that value when we call signHistory.add. Ergo the use of std::forwardon only the final use of the universal reference.

For std::move, the same thinking applies (i.e., apply std::moveto an rvalue reference the last time it's used), but it's important to note that in rare cases, you'll want to call std::move_if_noexceptinstead of std::move. To learn when and why, consult Item 14.

If you're in a function that returns by value , and you're returning an object bound to an rvalue reference or a universal reference, you'll want to apply std::moveor std::forwardwhen you return the reference. To see why, consider an operator+function to add two matrices together, where the left-hand matrix is known to be an rvalue (and can hence have its storage reused to hold the sum of the matrices):

Matrix // by-value return

operator+( Matrix&& lhs, const Matrix& rhs) {

lhs += rhs;

return std::move(lhs); // move lhs into

} // return value

By casting lhsto an rvalue in the returnstatement (via std::move), lhswill be moved into the function's return value location. If the call to std::movewere omitted,

Matrix // as above

operator+(Matrix&& lhs, const Matrix& rhs) {

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

Интервал:

Закладка:

Сделать

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

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


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

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

x